Open roaris opened 1 month ago
$ file checker
checker: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c2dd390ecbb794a78e20db0151832e9dd5c6359d, for GNU/Linux 3.2.0, not stripped
$ ./checker
flag? test
Wrong...
入力文字列はfgets関数で受け取っていて、rsp+0x30に格納される
fgets関数の第2引数は0x32になっていて、これには末尾のヌルバイト分も含まれるので、期待される文字列の長さは0x31(=49)であると分かる
実際、入力受け取り後のループは0x31回ループしている
rbxがループ変数である
ループ内の処理は、update関数の結果をmemcmp関数で検証している
memcmp関数は、メモリアドレス2つと長さを受け取り、長さ分、格納されている値を比較する関数である http://www9.plala.or.jp/sgwr-t/lib/memcmp.html
一致していれば0が返る
0が返ると、test eax, eax
でZFが1になり、setz al
でalが1になり、movzx eax, al
でeaxが1になる
1が返ると、eaxが0になり、r12dが0になり、Wrong...が表示される
memcmp関数の引数を確認する
lea r13, table
となっており、.dataに格納された初期値だと分かる次に、update関数を見るが、とても読めるものではない(Ghidraのdecompile結果を見ても、かなり厳しい) そのため、動的解析でなんとかしようと考える
コンテスト中はgdbスクリプトで解いた
main+0xafは、call _memcmp
の後のtest eax, eax
のアドレスである
call _memcmp
が終わった後のraxの値が0であるかを確かめている
gdb.execute(f'c {i}')
でi回continue出来る
import gdb
characters = '_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-.$@!?{} '
flag = 'Alpaca{'
for i in range(len(flag), 0x31):
for c in characters:
with open('input.txt', 'w') as f:
f.write(flag + c)
gdb.execute('r < input.txt')
gdb.execute('b *(main+0xaf)')
gdb.execute('r')
gdb.execute(f'c {i}')
rax = gdb.parse_and_eval('$rax')
if rax == 0:
flag += c
break
gdb checker -x solve.py > /dev/null
で実行して、input.txtを確認するとフラグが徐々に見えてくる
このプログラムの実行にはかなりの時間がかかる(40分ぐらいだった)
charactersで文字の順番を考えるのは重要
_は割と出てくるので、後ろの方に置くのは良くなく、一番前に置いた
gdb checker -x solve.py > /dev/null
はCtrl+Cで停止しないので、プロセスIDを調べてkillする必要がある
フラグはAlpaca{h4sh_4lgor1thm_1s_b4s3d_0n_MD5_4nd_keccak}
update関数は、MD5とKeccak(SHA-3)を組み合わせたものということかな
https://keymoon.hatenablog.com/entry/2024/10/07/230734 今回自分はgdbスクリプトで解いたが、他にもたくさん解法があるらしい というわけで、1つずつ試してみる
ltraceはバイナリが行う関数呼び出しをフックして追跡し、呼ばれた関数を引数や返り値と共にstderrに吐き出してくれる便利なプログラムです。
Alpaca{
に該当する部分のmemcmp関数の結果が0になっていることが分かる
memcmp関数に第4引数(9)があるのが謎
$ echo Alpaca{fakeflag} | ltrace ./checker > /dev/null
__printf_chk(1, 0x55fda56d8004, 0x7fffaef39d08, 0x55fda56d9da0) = 6
fgets("Alpaca{fakeflag}\n", 50, 0x7f86fb89f8e0) = 0x7fffaef39b80
memcmp(0x7fffaef39b50, 0x55fda56da020, 16, 9) = 0
memcmp(0x7fffaef39b50, 0x55fda56da030, 16, 9) = 0
memcmp(0x7fffaef39b50, 0x55fda56da040, 16, 9) = 0
memcmp(0x7fffaef39b50, 0x55fda56da050, 16, 9) = 0
memcmp(0x7fffaef39b50, 0x55fda56da060, 16, 9) = 0
memcmp(0x7fffaef39b50, 0x55fda56da070, 16, 9) = 0
memcmp(0x7fffaef39b50, 0x55fda56da080, 16, 9) = 0
memcmp(0x7fffaef39b50, 0x55fda56da090, 16, 9) = 105
memcmp(0x7fffaef39b50, 0x55fda56da0a0, 16, 9) = 8
memcmp(0x7fffaef39b50, 0x55fda56da0b0, 16, 9) = 0xffffff7d
memcmp(0x7fffaef39b50, 0x55fda56da0c0, 16, 9) = 64
memcmp(0x7fffaef39b50, 0x55fda56da0d0, 16, 9) = 41
memcmp(0x7fffaef39b50, 0x55fda56da0e0, 16, 9) = 0xffffff61
memcmp(0x7fffaef39b50, 0x55fda56da0f0, 16, 9) = 0xfffffff4
memcmp(0x7fffaef39b50, 0x55fda56da100, 16, 9) = 90
memcmp(0x7fffaef39b50, 0x55fda56da110, 16, 9) = 0xfffffffc
memcmp(0x7fffaef39b50, 0x55fda56da120, 16, 9) = 0xffffffac
memcmp(0x7fffaef39b50, 0x55fda56da130, 16, 9) = 0xffffffb7
memcmp(0x7fffaef39b50, 0x55fda56da140, 16, 9) = 0xffffff85
memcmp(0x7fffaef39b50, 0x55fda56da150, 16, 9) = 0xffffffc0
memcmp(0x7fffaef39b50, 0x55fda56da160, 16, 9) = 0xffffffaa
memcmp(0x7fffaef39b50, 0x55fda56da170, 16, 9) = 0xfffffffe
memcmp(0x7fffaef39b50, 0x55fda56da180, 16, 9) = 0xffffff73
memcmp(0x7fffaef39b50, 0x55fda56da190, 16, 9) = 0xffffffc4
memcmp(0x7fffaef39b50, 0x55fda56da1a0, 16, 9) = 0xffffffdc
memcmp(0x7fffaef39b50, 0x55fda56da1b0, 16, 9) = 0xffffffa4
memcmp(0x7fffaef39b50, 0x55fda56da1c0, 16, 9) = 15
memcmp(0x7fffaef39b50, 0x55fda56da1d0, 16, 9) = 39
memcmp(0x7fffaef39b50, 0x55fda56da1e0, 16, 9) = 0xffffffec
memcmp(0x7fffaef39b50, 0x55fda56da1f0, 16, 9) = 16
memcmp(0x7fffaef39b50, 0x55fda56da200, 16, 9) = 97
memcmp(0x7fffaef39b50, 0x55fda56da210, 16, 9) = 127
memcmp(0x7fffaef39b50, 0x55fda56da220, 16, 9) = 59
memcmp(0x7fffaef39b50, 0x55fda56da230, 16, 9) = 177
memcmp(0x7fffaef39b50, 0x55fda56da240, 16, 9) = 171
memcmp(0x7fffaef39b50, 0x55fda56da250, 16, 9) = 152
memcmp(0x7fffaef39b50, 0x55fda56da260, 16, 9) = 0xffffff7b
memcmp(0x7fffaef39b50, 0x55fda56da270, 16, 9) = 0xffffff75
memcmp(0x7fffaef39b50, 0x55fda56da280, 16, 9) = 0xffffffcb
memcmp(0x7fffaef39b50, 0x55fda56da290, 16, 9) = 0xffffffda
memcmp(0x7fffaef39b50, 0x55fda56da2a0, 16, 9) = 73
memcmp(0x7fffaef39b50, 0x55fda56da2b0, 16, 9) = 92
memcmp(0x7fffaef39b50, 0x55fda56da2c0, 16, 9) = 0xffffff83
memcmp(0x7fffaef39b50, 0x55fda56da2d0, 16, 9) = 88
memcmp(0x7fffaef39b50, 0x55fda56da2e0, 16, 9) = 41
memcmp(0x7fffaef39b50, 0x55fda56da2f0, 16, 9) = 43
memcmp(0x7fffaef39b50, 0x55fda56da300, 16, 9) = 65
memcmp(0x7fffaef39b50, 0x55fda56da310, 16, 9) = 0xfffffff3
memcmp(0x7fffaef39b50, 0x55fda56da320, 16, 9) = 57
puts("Wrong...") = 9
+++ exited (status 1) +++
tqdmで進捗出すの良い subprocessの使い方は https://qiita.com/caprest/items/0245a16825789b0263ad を見た
import subprocess
from tqdm import tqdm
def check(flag):
res = subprocess.run(f'echo {flag} | ltrace ./checker', shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
c = 0
for s in res.stderr.decode('ascii').split('\n'):
if s.startswith('memcmp'):
if s.split('=')[1][1:] == '0':
c += 1
else:
break
return len(flag) == c
flag = 'Alpaca{'
characters = '_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-.$@!?{} '
for i in tqdm(range(0x31 - len(flag))):
for c in characters:
if check(flag + c):
flag += c
break
print(flag)
LD_PRELOAD環境変数にshared objectファイルへのパスを渡すと、動的リンク時にshared object内に含まれる関数が他のどの関数よりも優先してリンクされるようになります。つまり、バイナリから呼んでいる外部の関数(ここではmemcmp)を自作の関数で上書きできるということです。
本来はlibc.so中のmemcmp関数を使っている
$ ldd checker
linux-vdso.so.1 (0x00007fffe71c3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efd5c59b000)
/lib64/ld-linux-x86-64.so.2 (0x00007efd5c7a3000)
hook.c
int memcmp(char *buf1, char *buf2, int len) {
for (int i = 0; i < len; i++) {
if (buf1[i] < buf2[i]) return -1;
if (buf1[i] > buf2[i]) return 1;
}
puts("ok");
return 0;
}
shared objectを作成 : gcc hook.c -shared -o hook.so
LD_PRELOAD環境変数を設定して実行
$ echo Alpaca{fakeflag} | LD_PRELOAD=./hook.so ./checker
flag? ok
ok
ok
ok
ok
ok
ok
Wrong...
import subprocess
from tqdm import tqdm
def check(flag):
res = subprocess.run(f'echo {flag} | LD_PRELOAD=./hook.so ./checker', shell=True, stdout=subprocess.PIPE)
return res.stdout.decode('ascii').count('ok') == len(flag)
flag = 'Alpaca{'
characters = '_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-.$@!?{} '
for i in tqdm(range(0x31 - len(flag))):
for c in characters:
if check(flag + c):
flag += c
break
print(flag)
前項では、動的リンカは関数名をもとにリンクしていると書きました。これはつまり、リンクに用いられている文字列を他の文字列に置き換えれば、別の関数がリンクされるようになるということです。
バイナリ中のmemcmpをputs\00\00に置き換える
import subprocess
res = open("checker", "rb").read()
open("checker_puts", "wb").write(res.replace(b'memcmp', b'puts\x00\x00'))
subprocess.run("chmod +x checker_puts", shell=True)
IDAで確認すると確かにmemcmpがputsに置き換わっている これによって、update関数の結果が出力されるようになる
しかし、putsではヌルバイト以降が出力されないため、正確にチェックすることが出来ない つまり、↓のtableの各行のヌルバイト以降は考慮出来ない update関数の結果が前の文字にも依存しているようなので(AlとBlを与えた時で、lのupdate関数の結果が異なる)、先頭から1文字ずつ確定させていく方法だと正しいフラグを得られない なので、dfsで全探索している
import subprocess
table = [
0x42, 0x3C, 0xF1, 0x21, 0xA3, 0x0F, 0x05, 0xAC, 0x57, 0xFD, 0x40, 0xB0, 0xA2, 0x14, 0x01, 0x98,
0x7D, 0x2E, 0xAD, 0x5D, 0xD6, 0x23, 0x77, 0xC1, 0x06, 0x7A, 0x50, 0xCB, 0xF8, 0xCD, 0x1D, 0xBC,
0xA8, 0x25, 0xD2, 0xDD, 0x9B, 0x73, 0x59, 0x16, 0x0D, 0xAD, 0x28, 0x22, 0xF9, 0x10, 0x81, 0x8A,
0x50, 0x52, 0x38, 0xAF, 0x80, 0x4F, 0x15, 0xF2, 0x9A, 0xBD, 0x06, 0x65, 0x75, 0x98, 0xA2, 0x7C,
0x49, 0x79, 0x7E, 0xD2, 0xDC, 0xDB, 0xFE, 0xC1, 0x36, 0xA3, 0xAA, 0x97, 0x1B, 0x00, 0xD2, 0x32,
0xBF, 0x81, 0x62, 0x0A, 0xBD, 0x10, 0x98, 0x1C, 0x8C, 0xD6, 0x33, 0x82, 0x2E, 0x93, 0x89, 0x46,
0x0F, 0x2E, 0xC0, 0x27, 0x82, 0x56, 0x0A, 0x1F, 0xD4, 0xC6, 0x32, 0x49, 0x93, 0xDE, 0x02, 0x5D,
0x90, 0x67, 0x9B, 0x06, 0x4C, 0xCB, 0x78, 0x0A, 0x6F, 0xF3, 0x9C, 0x0E, 0x5E, 0x8E, 0x3A, 0xD6,
0x93, 0x6F, 0x9C, 0xA1, 0x54, 0x8F, 0xC5, 0x0E, 0x48, 0x1B, 0x81, 0x31, 0xA6, 0x47, 0xD9, 0xE3,
0xC9, 0xCD, 0xA1, 0x7E, 0xAF, 0x46, 0x9A, 0xBC, 0xAD, 0x1C, 0xC8, 0xC0, 0x8C, 0x9D, 0xD9, 0x16,
0x9B, 0xD2, 0x22, 0x82, 0x35, 0xC3, 0xB0, 0x8F, 0x5A, 0x05, 0x55, 0x58, 0x45, 0xC5, 0xEB, 0x67,
0x0B, 0x17, 0xD6, 0xA2, 0x20, 0x8B, 0x6B, 0xB3, 0x1B, 0xB8, 0x88, 0x6F, 0xDD, 0x0C, 0x1C, 0x8F,
0xE9, 0x5E, 0x28, 0xB3, 0x05, 0x4B, 0x52, 0x9B, 0x83, 0xFA, 0xBA, 0x1A, 0xBD, 0x5D, 0x7E, 0xD5,
0xDD, 0x95, 0x7F, 0x8D, 0x26, 0xA0, 0xFB, 0x1A, 0xE5, 0x30, 0xAD, 0xAA, 0x01, 0xB7, 0x9E, 0x1E,
0x10, 0xFA, 0xAC, 0x9C, 0x72, 0x57, 0x2A, 0x7B, 0xE3, 0xC6, 0x1B, 0x8B, 0xED, 0xFD, 0x98, 0xBF,
0xE1, 0x4F, 0x56, 0x87, 0x7E, 0x8F, 0xD9, 0xBA, 0xD6, 0x5C, 0x79, 0x4A, 0x43, 0x57, 0x0C, 0x80,
0xB0, 0x19, 0xD8, 0x42, 0x6B, 0x2F, 0x25, 0xDF, 0x59, 0xAA, 0xDD, 0x54, 0x12, 0x35, 0xA9, 0x18,
0x8A, 0xAC, 0x3F, 0x6A, 0x22, 0x6E, 0x44, 0x7D, 0x13, 0x7D, 0x4B, 0x18, 0x5D, 0xD3, 0xC1, 0x86,
0x86, 0xD5, 0xB6, 0xF4, 0x47, 0x9B, 0x26, 0xC2, 0xE3, 0xA4, 0xE0, 0x12, 0x9E, 0xCF, 0x12, 0xF5,
0xED, 0xFC, 0x70, 0x4D, 0xFF, 0xB9, 0x2C, 0x0A, 0xBF, 0xAA, 0x86, 0x4D, 0x07, 0xFF, 0x22, 0x9E,
0x9A, 0xD2, 0x87, 0xE3, 0x66, 0x15, 0xB4, 0x19, 0x27, 0xD1, 0xEB, 0xB1, 0x76, 0xE8, 0x48, 0x12,
0x59, 0xAF, 0xF1, 0x82, 0x9B, 0x31, 0x92, 0xE6, 0xDD, 0x80, 0x23, 0x3A, 0x3F, 0x9C, 0xD6, 0x82,
0x99, 0xF3, 0x98, 0x60, 0x8F, 0xD0, 0x39, 0xD5, 0x9C, 0x97, 0x0F, 0xEF, 0xE6, 0x8C, 0xF8, 0x42,
0x7A, 0x9D, 0xA9, 0x51, 0x89, 0x13, 0xEE, 0x7B, 0x47, 0x30, 0xFA, 0x14, 0x86, 0x2F, 0x1A, 0xD8,
0xDD, 0x09, 0x78, 0xB5, 0x9C, 0x41, 0xC9, 0x62, 0x7D, 0x0F, 0xC8, 0x73, 0x42, 0x91, 0x63, 0x07,
0xED, 0xF9, 0x23, 0xB8, 0x73, 0x7F, 0xC1, 0xC6, 0xF6, 0xF6, 0x9F, 0x01, 0xD5, 0xA7, 0x29, 0x44,
0x43, 0x43, 0x02, 0x52, 0x2C, 0xB5, 0x2F, 0xAF, 0x55, 0x63, 0x48, 0x7B, 0x55, 0x9D, 0x45, 0xD9,
0x94, 0x52, 0x64, 0x6B, 0xD3, 0x1B, 0xB6, 0xFC, 0x10, 0xAF, 0xEA, 0x55, 0x9A, 0xEC, 0x00, 0xFA,
0x5A, 0x0E, 0x1C, 0xEF, 0x10, 0x9A, 0x7F, 0xD2, 0xAB, 0x20, 0xCD, 0x8D, 0x8D, 0xCF, 0x88, 0x33,
0x10, 0xE4, 0x11, 0xAD, 0xE1, 0x7F, 0x7C, 0x59, 0x7F, 0x29, 0xF6, 0xBB, 0x32, 0x0E, 0xA8, 0xD9,
0x7B, 0xFA, 0x37, 0xA0, 0x41, 0xB3, 0x12, 0xA4, 0xD6, 0x30, 0xE6, 0xD9, 0x7B, 0x1A, 0xDB, 0x53,
0x2A, 0xCC, 0x13, 0x23, 0xEA, 0x09, 0xDA, 0x46, 0x5D, 0xF0, 0x25, 0x46, 0x96, 0xD3, 0x64, 0xD7,
0x98, 0x8E, 0x85, 0x8C, 0xF4, 0xFD, 0x85, 0x12, 0xC3, 0x00, 0x6D, 0x0B, 0xD1, 0xFF, 0xE3, 0xB6,
0x10, 0x35, 0x8B, 0x36, 0x48, 0x5B, 0x7C, 0x69, 0x77, 0xFB, 0x15, 0x65, 0xF1, 0xA5, 0x15, 0xC4,
0x07, 0x2C, 0xD5, 0x81, 0xB2, 0x1F, 0x25, 0x20, 0x6F, 0x48, 0xE0, 0x4C, 0x24, 0x54, 0xE9, 0xC2,
0x00, 0x62, 0x08, 0x9D, 0x7A, 0x10, 0x32, 0xB2, 0x7C, 0xBB, 0x5A, 0x51, 0xDB, 0xBF, 0xFB, 0xE1,
0xAF, 0x20, 0x81, 0x11, 0xCE, 0xA1, 0x9F, 0x79, 0x36, 0x2C, 0x8A, 0xB3, 0x0C, 0xF0, 0xDF, 0x38,
0x9C, 0xC9, 0x1D, 0x25, 0xEF, 0xDF, 0x4F, 0x6C, 0xC5, 0x3B, 0x74, 0x6F, 0x9D, 0xAD, 0x36, 0x05,
0x67, 0xC5, 0x9A, 0xAE, 0x2D, 0x6D, 0xAA, 0xDB, 0x0E, 0xE0, 0xA6, 0x67, 0x45, 0xC5, 0x8E, 0xF8,
0xC2, 0x1E, 0x64, 0xB8, 0x64, 0xA1, 0x46, 0x18, 0x2D, 0x4A, 0xBA, 0x67, 0x8A, 0x30, 0xB5, 0x75,
0x05, 0x20, 0x96, 0x0D, 0xCE, 0xCC, 0xEC, 0x1F, 0x8C, 0xFD, 0xB0, 0x4F, 0xCD, 0x4C, 0x35, 0x46,
0x35, 0x7D, 0xD1, 0xF5, 0x83, 0xC7, 0xA3, 0x2E, 0x2E, 0x33, 0x30, 0x1C, 0x92, 0xC9, 0x54, 0xAA,
0xD2, 0x0F, 0x66, 0x51, 0x50, 0x85, 0x72, 0x6D, 0xBF, 0x8C, 0x57, 0x73, 0xA0, 0xD9, 0xBD, 0x72,
0x75, 0x5A, 0xE1, 0x3B, 0x98, 0x06, 0x7D, 0x99, 0x4F, 0xBE, 0xA3, 0xB3, 0x63, 0xB2, 0xD0, 0x18,
0x17, 0xE9, 0xC1, 0xEA, 0x3B, 0x90, 0x04, 0x57, 0xB4, 0x52, 0xDC, 0x28, 0x33, 0xE1, 0x71, 0x84,
0x97, 0xA7, 0xE2, 0xAD, 0xBB, 0xBC, 0xAB, 0xBB, 0xF2, 0x17, 0x5D, 0xC8, 0xEE, 0xE5, 0x32, 0xF8,
0x9C, 0x32, 0x27, 0x10, 0x5B, 0x20, 0x7B, 0x12, 0x46, 0x3D, 0xC2, 0x89, 0x15, 0x6F, 0xB9, 0x1B,
0x32, 0xEE, 0x5D, 0x7A, 0x8E, 0x13, 0x33, 0x8B, 0xE5, 0x36, 0x60, 0xAA, 0x38, 0x53, 0x50, 0x74,
0xB2, 0x86, 0x92, 0x5F, 0xA0, 0xFB, 0xC6, 0xEE, 0x0C, 0xCE, 0xDA, 0xA2, 0xFE, 0x5D, 0x35, 0xEA,
]
def check(flag):
res = subprocess.run(f'echo {flag} | ./checker_puts', shell=True, stdout=subprocess.PIPE)
b = list(res.stdout)
l = len(flag)
t = table[16*(l-1):16*l]
for i in range(16):
if t[i] == 0x00:
t = t[:i]
break
ok = False
for i in range(len(b) - len(t) + 1):
if b[i:i+len(t)] == t:
ok = True
if not ok:
return None
if len(flag) == 0x31:
return flag
for c in characters:
f = check(flag + c)
if f:
return f
return None
flag = 'Alpaca{'
characters = '_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-.$@!?{} '
print(check(flag))
今回、update関数内に動作に必要な関数呼び出しは存在しません。そのため、update関数は直接別のところに持っていったとしても動きそうです。今回は、実行可能にしたstackにシェルコードのような形で関数のデータを置き、それを呼び出すという手法をとります。
executor.c update関数の出力が36バイトなのは、どうやって気付けば良いのか分からない
int main() {
char update[] = { FUNC };
char buf[36];
read(0, &buf, 36);
char c;
read(0, &c, 1);
((void(*)(char*, char))update)(buf, c);
write(1, &buf, 36);
}
update関数のサイズ(0x7B0)はIDAやobjdumpの結果から分かる 記事では0x7A9になっているが、最後のnop命令を除くと、0x7A9になる -Dは https://qiita.com/bdpumpkin/items/867851cb5df2d836f940 を見ると分かる -z execstackで、NX Bitを無効にし、スタック上に置いたコードを実行可能にする
import subprocess
from pwn import ELF
elf = ELF('./checker', checksec=False)
update = elf.read(elf.symbols['update'], 0x7B0)
subprocess.run(f'gcc -z execstack -DFUNC={','.join(map(str, update))} -o executor executor.c', shell=True)
update関数の中で36バイトの内部状態を扱っていることに気付けないと書けないと思う(どうやって気付けば良いのか分からない)
import subprocess
from tqdm import tqdm
table = [
0x42, 0x3C, 0xF1, 0x21, 0xA3, 0x0F, 0x05, 0xAC, 0x57, 0xFD, 0x40, 0xB0, 0xA2, 0x14, 0x01, 0x98,
0x7D, 0x2E, 0xAD, 0x5D, 0xD6, 0x23, 0x77, 0xC1, 0x06, 0x7A, 0x50, 0xCB, 0xF8, 0xCD, 0x1D, 0xBC,
0xA8, 0x25, 0xD2, 0xDD, 0x9B, 0x73, 0x59, 0x16, 0x0D, 0xAD, 0x28, 0x22, 0xF9, 0x10, 0x81, 0x8A,
0x50, 0x52, 0x38, 0xAF, 0x80, 0x4F, 0x15, 0xF2, 0x9A, 0xBD, 0x06, 0x65, 0x75, 0x98, 0xA2, 0x7C,
0x49, 0x79, 0x7E, 0xD2, 0xDC, 0xDB, 0xFE, 0xC1, 0x36, 0xA3, 0xAA, 0x97, 0x1B, 0x00, 0xD2, 0x32,
0xBF, 0x81, 0x62, 0x0A, 0xBD, 0x10, 0x98, 0x1C, 0x8C, 0xD6, 0x33, 0x82, 0x2E, 0x93, 0x89, 0x46,
0x0F, 0x2E, 0xC0, 0x27, 0x82, 0x56, 0x0A, 0x1F, 0xD4, 0xC6, 0x32, 0x49, 0x93, 0xDE, 0x02, 0x5D,
0x90, 0x67, 0x9B, 0x06, 0x4C, 0xCB, 0x78, 0x0A, 0x6F, 0xF3, 0x9C, 0x0E, 0x5E, 0x8E, 0x3A, 0xD6,
0x93, 0x6F, 0x9C, 0xA1, 0x54, 0x8F, 0xC5, 0x0E, 0x48, 0x1B, 0x81, 0x31, 0xA6, 0x47, 0xD9, 0xE3,
0xC9, 0xCD, 0xA1, 0x7E, 0xAF, 0x46, 0x9A, 0xBC, 0xAD, 0x1C, 0xC8, 0xC0, 0x8C, 0x9D, 0xD9, 0x16,
0x9B, 0xD2, 0x22, 0x82, 0x35, 0xC3, 0xB0, 0x8F, 0x5A, 0x05, 0x55, 0x58, 0x45, 0xC5, 0xEB, 0x67,
0x0B, 0x17, 0xD6, 0xA2, 0x20, 0x8B, 0x6B, 0xB3, 0x1B, 0xB8, 0x88, 0x6F, 0xDD, 0x0C, 0x1C, 0x8F,
0xE9, 0x5E, 0x28, 0xB3, 0x05, 0x4B, 0x52, 0x9B, 0x83, 0xFA, 0xBA, 0x1A, 0xBD, 0x5D, 0x7E, 0xD5,
0xDD, 0x95, 0x7F, 0x8D, 0x26, 0xA0, 0xFB, 0x1A, 0xE5, 0x30, 0xAD, 0xAA, 0x01, 0xB7, 0x9E, 0x1E,
0x10, 0xFA, 0xAC, 0x9C, 0x72, 0x57, 0x2A, 0x7B, 0xE3, 0xC6, 0x1B, 0x8B, 0xED, 0xFD, 0x98, 0xBF,
0xE1, 0x4F, 0x56, 0x87, 0x7E, 0x8F, 0xD9, 0xBA, 0xD6, 0x5C, 0x79, 0x4A, 0x43, 0x57, 0x0C, 0x80,
0xB0, 0x19, 0xD8, 0x42, 0x6B, 0x2F, 0x25, 0xDF, 0x59, 0xAA, 0xDD, 0x54, 0x12, 0x35, 0xA9, 0x18,
0x8A, 0xAC, 0x3F, 0x6A, 0x22, 0x6E, 0x44, 0x7D, 0x13, 0x7D, 0x4B, 0x18, 0x5D, 0xD3, 0xC1, 0x86,
0x86, 0xD5, 0xB6, 0xF4, 0x47, 0x9B, 0x26, 0xC2, 0xE3, 0xA4, 0xE0, 0x12, 0x9E, 0xCF, 0x12, 0xF5,
0xED, 0xFC, 0x70, 0x4D, 0xFF, 0xB9, 0x2C, 0x0A, 0xBF, 0xAA, 0x86, 0x4D, 0x07, 0xFF, 0x22, 0x9E,
0x9A, 0xD2, 0x87, 0xE3, 0x66, 0x15, 0xB4, 0x19, 0x27, 0xD1, 0xEB, 0xB1, 0x76, 0xE8, 0x48, 0x12,
0x59, 0xAF, 0xF1, 0x82, 0x9B, 0x31, 0x92, 0xE6, 0xDD, 0x80, 0x23, 0x3A, 0x3F, 0x9C, 0xD6, 0x82,
0x99, 0xF3, 0x98, 0x60, 0x8F, 0xD0, 0x39, 0xD5, 0x9C, 0x97, 0x0F, 0xEF, 0xE6, 0x8C, 0xF8, 0x42,
0x7A, 0x9D, 0xA9, 0x51, 0x89, 0x13, 0xEE, 0x7B, 0x47, 0x30, 0xFA, 0x14, 0x86, 0x2F, 0x1A, 0xD8,
0xDD, 0x09, 0x78, 0xB5, 0x9C, 0x41, 0xC9, 0x62, 0x7D, 0x0F, 0xC8, 0x73, 0x42, 0x91, 0x63, 0x07,
0xED, 0xF9, 0x23, 0xB8, 0x73, 0x7F, 0xC1, 0xC6, 0xF6, 0xF6, 0x9F, 0x01, 0xD5, 0xA7, 0x29, 0x44,
0x43, 0x43, 0x02, 0x52, 0x2C, 0xB5, 0x2F, 0xAF, 0x55, 0x63, 0x48, 0x7B, 0x55, 0x9D, 0x45, 0xD9,
0x94, 0x52, 0x64, 0x6B, 0xD3, 0x1B, 0xB6, 0xFC, 0x10, 0xAF, 0xEA, 0x55, 0x9A, 0xEC, 0x00, 0xFA,
0x5A, 0x0E, 0x1C, 0xEF, 0x10, 0x9A, 0x7F, 0xD2, 0xAB, 0x20, 0xCD, 0x8D, 0x8D, 0xCF, 0x88, 0x33,
0x10, 0xE4, 0x11, 0xAD, 0xE1, 0x7F, 0x7C, 0x59, 0x7F, 0x29, 0xF6, 0xBB, 0x32, 0x0E, 0xA8, 0xD9,
0x7B, 0xFA, 0x37, 0xA0, 0x41, 0xB3, 0x12, 0xA4, 0xD6, 0x30, 0xE6, 0xD9, 0x7B, 0x1A, 0xDB, 0x53,
0x2A, 0xCC, 0x13, 0x23, 0xEA, 0x09, 0xDA, 0x46, 0x5D, 0xF0, 0x25, 0x46, 0x96, 0xD3, 0x64, 0xD7,
0x98, 0x8E, 0x85, 0x8C, 0xF4, 0xFD, 0x85, 0x12, 0xC3, 0x00, 0x6D, 0x0B, 0xD1, 0xFF, 0xE3, 0xB6,
0x10, 0x35, 0x8B, 0x36, 0x48, 0x5B, 0x7C, 0x69, 0x77, 0xFB, 0x15, 0x65, 0xF1, 0xA5, 0x15, 0xC4,
0x07, 0x2C, 0xD5, 0x81, 0xB2, 0x1F, 0x25, 0x20, 0x6F, 0x48, 0xE0, 0x4C, 0x24, 0x54, 0xE9, 0xC2,
0x00, 0x62, 0x08, 0x9D, 0x7A, 0x10, 0x32, 0xB2, 0x7C, 0xBB, 0x5A, 0x51, 0xDB, 0xBF, 0xFB, 0xE1,
0xAF, 0x20, 0x81, 0x11, 0xCE, 0xA1, 0x9F, 0x79, 0x36, 0x2C, 0x8A, 0xB3, 0x0C, 0xF0, 0xDF, 0x38,
0x9C, 0xC9, 0x1D, 0x25, 0xEF, 0xDF, 0x4F, 0x6C, 0xC5, 0x3B, 0x74, 0x6F, 0x9D, 0xAD, 0x36, 0x05,
0x67, 0xC5, 0x9A, 0xAE, 0x2D, 0x6D, 0xAA, 0xDB, 0x0E, 0xE0, 0xA6, 0x67, 0x45, 0xC5, 0x8E, 0xF8,
0xC2, 0x1E, 0x64, 0xB8, 0x64, 0xA1, 0x46, 0x18, 0x2D, 0x4A, 0xBA, 0x67, 0x8A, 0x30, 0xB5, 0x75,
0x05, 0x20, 0x96, 0x0D, 0xCE, 0xCC, 0xEC, 0x1F, 0x8C, 0xFD, 0xB0, 0x4F, 0xCD, 0x4C, 0x35, 0x46,
0x35, 0x7D, 0xD1, 0xF5, 0x83, 0xC7, 0xA3, 0x2E, 0x2E, 0x33, 0x30, 0x1C, 0x92, 0xC9, 0x54, 0xAA,
0xD2, 0x0F, 0x66, 0x51, 0x50, 0x85, 0x72, 0x6D, 0xBF, 0x8C, 0x57, 0x73, 0xA0, 0xD9, 0xBD, 0x72,
0x75, 0x5A, 0xE1, 0x3B, 0x98, 0x06, 0x7D, 0x99, 0x4F, 0xBE, 0xA3, 0xB3, 0x63, 0xB2, 0xD0, 0x18,
0x17, 0xE9, 0xC1, 0xEA, 0x3B, 0x90, 0x04, 0x57, 0xB4, 0x52, 0xDC, 0x28, 0x33, 0xE1, 0x71, 0x84,
0x97, 0xA7, 0xE2, 0xAD, 0xBB, 0xBC, 0xAB, 0xBB, 0xF2, 0x17, 0x5D, 0xC8, 0xEE, 0xE5, 0x32, 0xF8,
0x9C, 0x32, 0x27, 0x10, 0x5B, 0x20, 0x7B, 0x12, 0x46, 0x3D, 0xC2, 0x89, 0x15, 0x6F, 0xB9, 0x1B,
0x32, 0xEE, 0x5D, 0x7A, 0x8E, 0x13, 0x33, 0x8B, 0xE5, 0x36, 0x60, 0xAA, 0x38, 0x53, 0x50, 0x74,
0xB2, 0x86, 0x92, 0x5F, 0xA0, 0xFB, 0xC6, 0xEE, 0x0C, 0xCE, 0xDA, 0xA2, 0xFE, 0x5D, 0x35, 0xEA,
]
flag = ''
characters = '_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-.$@!?{} '
state = b'\x00' * 36
for i in tqdm(range(0x31)):
for c in characters:
res = subprocess.run(f'./executor', input=state+bytes(c, 'ascii'), shell=True, stdout=subprocess.PIPE).stdout
if list(res[:16]) == table[16*i:16*i+16]:
state = res
flag += c
print(flag)
Pythonには共有ライブラリを読み込んで、その関数をPythonから実行するためのctypesというライブラリが存在します。
shared objectを作るコード
bin[lief.ELF.DynamicEntry.TAG.FLAGS_1].remove(lief.ELF.DynamicEntryFlags.FLAG.PIE)
は何か分からない
import lief
bin = lief.parse("./checker")
bin.add_exported_function(bin.get_function_address("update"), "update")
bin[lief.ELF.DynamicEntry.TAG.FLAGS_1].remove(lief.ELF.DynamicEntryFlags.FLAG.PIE)
bin.write("checker.so")
import ctypes
import subprocess
from tqdm import tqdm
table = [
0x42, 0x3C, 0xF1, 0x21, 0xA3, 0x0F, 0x05, 0xAC, 0x57, 0xFD, 0x40, 0xB0, 0xA2, 0x14, 0x01, 0x98,
0x7D, 0x2E, 0xAD, 0x5D, 0xD6, 0x23, 0x77, 0xC1, 0x06, 0x7A, 0x50, 0xCB, 0xF8, 0xCD, 0x1D, 0xBC,
0xA8, 0x25, 0xD2, 0xDD, 0x9B, 0x73, 0x59, 0x16, 0x0D, 0xAD, 0x28, 0x22, 0xF9, 0x10, 0x81, 0x8A,
0x50, 0x52, 0x38, 0xAF, 0x80, 0x4F, 0x15, 0xF2, 0x9A, 0xBD, 0x06, 0x65, 0x75, 0x98, 0xA2, 0x7C,
0x49, 0x79, 0x7E, 0xD2, 0xDC, 0xDB, 0xFE, 0xC1, 0x36, 0xA3, 0xAA, 0x97, 0x1B, 0x00, 0xD2, 0x32,
0xBF, 0x81, 0x62, 0x0A, 0xBD, 0x10, 0x98, 0x1C, 0x8C, 0xD6, 0x33, 0x82, 0x2E, 0x93, 0x89, 0x46,
0x0F, 0x2E, 0xC0, 0x27, 0x82, 0x56, 0x0A, 0x1F, 0xD4, 0xC6, 0x32, 0x49, 0x93, 0xDE, 0x02, 0x5D,
0x90, 0x67, 0x9B, 0x06, 0x4C, 0xCB, 0x78, 0x0A, 0x6F, 0xF3, 0x9C, 0x0E, 0x5E, 0x8E, 0x3A, 0xD6,
0x93, 0x6F, 0x9C, 0xA1, 0x54, 0x8F, 0xC5, 0x0E, 0x48, 0x1B, 0x81, 0x31, 0xA6, 0x47, 0xD9, 0xE3,
0xC9, 0xCD, 0xA1, 0x7E, 0xAF, 0x46, 0x9A, 0xBC, 0xAD, 0x1C, 0xC8, 0xC0, 0x8C, 0x9D, 0xD9, 0x16,
0x9B, 0xD2, 0x22, 0x82, 0x35, 0xC3, 0xB0, 0x8F, 0x5A, 0x05, 0x55, 0x58, 0x45, 0xC5, 0xEB, 0x67,
0x0B, 0x17, 0xD6, 0xA2, 0x20, 0x8B, 0x6B, 0xB3, 0x1B, 0xB8, 0x88, 0x6F, 0xDD, 0x0C, 0x1C, 0x8F,
0xE9, 0x5E, 0x28, 0xB3, 0x05, 0x4B, 0x52, 0x9B, 0x83, 0xFA, 0xBA, 0x1A, 0xBD, 0x5D, 0x7E, 0xD5,
0xDD, 0x95, 0x7F, 0x8D, 0x26, 0xA0, 0xFB, 0x1A, 0xE5, 0x30, 0xAD, 0xAA, 0x01, 0xB7, 0x9E, 0x1E,
0x10, 0xFA, 0xAC, 0x9C, 0x72, 0x57, 0x2A, 0x7B, 0xE3, 0xC6, 0x1B, 0x8B, 0xED, 0xFD, 0x98, 0xBF,
0xE1, 0x4F, 0x56, 0x87, 0x7E, 0x8F, 0xD9, 0xBA, 0xD6, 0x5C, 0x79, 0x4A, 0x43, 0x57, 0x0C, 0x80,
0xB0, 0x19, 0xD8, 0x42, 0x6B, 0x2F, 0x25, 0xDF, 0x59, 0xAA, 0xDD, 0x54, 0x12, 0x35, 0xA9, 0x18,
0x8A, 0xAC, 0x3F, 0x6A, 0x22, 0x6E, 0x44, 0x7D, 0x13, 0x7D, 0x4B, 0x18, 0x5D, 0xD3, 0xC1, 0x86,
0x86, 0xD5, 0xB6, 0xF4, 0x47, 0x9B, 0x26, 0xC2, 0xE3, 0xA4, 0xE0, 0x12, 0x9E, 0xCF, 0x12, 0xF5,
0xED, 0xFC, 0x70, 0x4D, 0xFF, 0xB9, 0x2C, 0x0A, 0xBF, 0xAA, 0x86, 0x4D, 0x07, 0xFF, 0x22, 0x9E,
0x9A, 0xD2, 0x87, 0xE3, 0x66, 0x15, 0xB4, 0x19, 0x27, 0xD1, 0xEB, 0xB1, 0x76, 0xE8, 0x48, 0x12,
0x59, 0xAF, 0xF1, 0x82, 0x9B, 0x31, 0x92, 0xE6, 0xDD, 0x80, 0x23, 0x3A, 0x3F, 0x9C, 0xD6, 0x82,
0x99, 0xF3, 0x98, 0x60, 0x8F, 0xD0, 0x39, 0xD5, 0x9C, 0x97, 0x0F, 0xEF, 0xE6, 0x8C, 0xF8, 0x42,
0x7A, 0x9D, 0xA9, 0x51, 0x89, 0x13, 0xEE, 0x7B, 0x47, 0x30, 0xFA, 0x14, 0x86, 0x2F, 0x1A, 0xD8,
0xDD, 0x09, 0x78, 0xB5, 0x9C, 0x41, 0xC9, 0x62, 0x7D, 0x0F, 0xC8, 0x73, 0x42, 0x91, 0x63, 0x07,
0xED, 0xF9, 0x23, 0xB8, 0x73, 0x7F, 0xC1, 0xC6, 0xF6, 0xF6, 0x9F, 0x01, 0xD5, 0xA7, 0x29, 0x44,
0x43, 0x43, 0x02, 0x52, 0x2C, 0xB5, 0x2F, 0xAF, 0x55, 0x63, 0x48, 0x7B, 0x55, 0x9D, 0x45, 0xD9,
0x94, 0x52, 0x64, 0x6B, 0xD3, 0x1B, 0xB6, 0xFC, 0x10, 0xAF, 0xEA, 0x55, 0x9A, 0xEC, 0x00, 0xFA,
0x5A, 0x0E, 0x1C, 0xEF, 0x10, 0x9A, 0x7F, 0xD2, 0xAB, 0x20, 0xCD, 0x8D, 0x8D, 0xCF, 0x88, 0x33,
0x10, 0xE4, 0x11, 0xAD, 0xE1, 0x7F, 0x7C, 0x59, 0x7F, 0x29, 0xF6, 0xBB, 0x32, 0x0E, 0xA8, 0xD9,
0x7B, 0xFA, 0x37, 0xA0, 0x41, 0xB3, 0x12, 0xA4, 0xD6, 0x30, 0xE6, 0xD9, 0x7B, 0x1A, 0xDB, 0x53,
0x2A, 0xCC, 0x13, 0x23, 0xEA, 0x09, 0xDA, 0x46, 0x5D, 0xF0, 0x25, 0x46, 0x96, 0xD3, 0x64, 0xD7,
0x98, 0x8E, 0x85, 0x8C, 0xF4, 0xFD, 0x85, 0x12, 0xC3, 0x00, 0x6D, 0x0B, 0xD1, 0xFF, 0xE3, 0xB6,
0x10, 0x35, 0x8B, 0x36, 0x48, 0x5B, 0x7C, 0x69, 0x77, 0xFB, 0x15, 0x65, 0xF1, 0xA5, 0x15, 0xC4,
0x07, 0x2C, 0xD5, 0x81, 0xB2, 0x1F, 0x25, 0x20, 0x6F, 0x48, 0xE0, 0x4C, 0x24, 0x54, 0xE9, 0xC2,
0x00, 0x62, 0x08, 0x9D, 0x7A, 0x10, 0x32, 0xB2, 0x7C, 0xBB, 0x5A, 0x51, 0xDB, 0xBF, 0xFB, 0xE1,
0xAF, 0x20, 0x81, 0x11, 0xCE, 0xA1, 0x9F, 0x79, 0x36, 0x2C, 0x8A, 0xB3, 0x0C, 0xF0, 0xDF, 0x38,
0x9C, 0xC9, 0x1D, 0x25, 0xEF, 0xDF, 0x4F, 0x6C, 0xC5, 0x3B, 0x74, 0x6F, 0x9D, 0xAD, 0x36, 0x05,
0x67, 0xC5, 0x9A, 0xAE, 0x2D, 0x6D, 0xAA, 0xDB, 0x0E, 0xE0, 0xA6, 0x67, 0x45, 0xC5, 0x8E, 0xF8,
0xC2, 0x1E, 0x64, 0xB8, 0x64, 0xA1, 0x46, 0x18, 0x2D, 0x4A, 0xBA, 0x67, 0x8A, 0x30, 0xB5, 0x75,
0x05, 0x20, 0x96, 0x0D, 0xCE, 0xCC, 0xEC, 0x1F, 0x8C, 0xFD, 0xB0, 0x4F, 0xCD, 0x4C, 0x35, 0x46,
0x35, 0x7D, 0xD1, 0xF5, 0x83, 0xC7, 0xA3, 0x2E, 0x2E, 0x33, 0x30, 0x1C, 0x92, 0xC9, 0x54, 0xAA,
0xD2, 0x0F, 0x66, 0x51, 0x50, 0x85, 0x72, 0x6D, 0xBF, 0x8C, 0x57, 0x73, 0xA0, 0xD9, 0xBD, 0x72,
0x75, 0x5A, 0xE1, 0x3B, 0x98, 0x06, 0x7D, 0x99, 0x4F, 0xBE, 0xA3, 0xB3, 0x63, 0xB2, 0xD0, 0x18,
0x17, 0xE9, 0xC1, 0xEA, 0x3B, 0x90, 0x04, 0x57, 0xB4, 0x52, 0xDC, 0x28, 0x33, 0xE1, 0x71, 0x84,
0x97, 0xA7, 0xE2, 0xAD, 0xBB, 0xBC, 0xAB, 0xBB, 0xF2, 0x17, 0x5D, 0xC8, 0xEE, 0xE5, 0x32, 0xF8,
0x9C, 0x32, 0x27, 0x10, 0x5B, 0x20, 0x7B, 0x12, 0x46, 0x3D, 0xC2, 0x89, 0x15, 0x6F, 0xB9, 0x1B,
0x32, 0xEE, 0x5D, 0x7A, 0x8E, 0x13, 0x33, 0x8B, 0xE5, 0x36, 0x60, 0xAA, 0x38, 0x53, 0x50, 0x74,
0xB2, 0x86, 0x92, 0x5F, 0xA0, 0xFB, 0xC6, 0xEE, 0x0C, 0xCE, 0xDA, 0xA2, 0xFE, 0x5D, 0x35, 0xEA,
]
flag = ''
characters = '_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-.$@!?{} '
state = b'\x00' * 36
lib = ctypes.CDLL('./checker.so')
for i in tqdm(range(0x31)):
for c in characters:
state_array = ctypes.create_string_buffer(state)
lib.update(state_array, ctypes.c_char(bytes(c, 'ascii')))
res = bytes(state_array)
if list(res[:16]) == table[16*i:16*i+16]:
state = res
flag += c
print(flag)
https://alpacahack.com/challenges/simple-flag-checker