picoCTF Practice Writeup 6
picoGym Practice Challenges page=6 の9問を勉強した記録
Compress and Attack は,python2 の import socket でブルートフォースに成功したので,チョーうれしい。(ソケット通信,フラグの総当たり攻撃)
このページの難問は,
442 solves の Play Nice (ジャンルはCryptographyだけど,ほぼpython力)
471 solves の Some Assembly Required 2
209 solves の gogo (Ghidraを使用したReverse Engineering)
490 solves の Milkslap (ステガノグラフィー)
182 solves の Compress and Attack (圧縮比に着目したブルートフォース)
340 solves の Super Serial (安全でないデシリアライゼーション)
Double DES と Scrambled: RSA はギブアップ。
Disk, disk, sleuth!
Description:
Use srch_strings
from the sleuthkit and some terminal-fu to find a flag in this disk image: dds1-alpine.flag.img.gz
Hints
- Have you ever used
file
to determine what a file was? - Relevant terminal-fu in picoGym: https://play.picoctf.org/practice/challenge/85
- Mastering this terminal-fu would enable you to find the flag in a single command: https://play.picoctf.org/practice/challenge/48
- Using your own computer, you could use qemu to boot from this disk!
Solution:
fileコマンドで何ファイルか確認する。
$ file dds1-alpine.flag.img
dds1-alpine.flag.img: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,32,33), end-CHS (0x10,81,1), startsector 2048, 260096 sectors
Play Nice
Category: Cryptography
Description
Not all ancient ciphers were so bad... The flag is not in standard format. nc mercury.picoctf.net 6057 playfair.py
Hints
(None)
#!/usr/bin/python3 -u
import signal
SQUARE_SIZE = 6
def generate_square(alphabet):
assert len(alphabet) == pow(SQUARE_SIZE, 2)
matrix = []
for i, letter in enumerate(alphabet):
if i % SQUARE_SIZE == 0:
row = []
row.append(letter)
if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
matrix.append(row)
return matrix
def get_index(letter, matrix):
for row in range(SQUARE_SIZE):
for col in range(SQUARE_SIZE):
if matrix[row][col] == letter:
return (row, col)
print("letter not found in matrix.")
exit()
def encrypt_pair(pair, matrix):
p1 = get_index(pair[0], matrix)
p2 = get_index(pair[1], matrix)
if p1[0] == p2[0]:
return matrix[p1[0]][(p1[1] + 1) % SQUARE_SIZE] + matrix[p2[0]][(p2[1] + 1) % SQUARE_SIZE]
elif p1[1] == p2[1]:
return matrix[(p1[0] + 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] + 1) % SQUARE_SIZE][p2[1]]
else:
return matrix[p1[0]][p2[1]] + matrix[p2[0]][p1[1]]
def encrypt_string(s, matrix):
result = ""
if len(s) % 2 == 0:
plain = s
else:
plain = s + "meiktp6yh4wxruavj9no13fb8d027c5glzsq"[0]
for i in range(0, len(plain), 2):
result += encrypt_pair(plain[i:i + 2], matrix)
return result
alphabet = open("key").read().rstrip()
m = generate_square(alphabet)
msg = open("msg").read().rstrip()
enc_msg = encrypt_string(msg, m)
print("Here is the alphabet: {}\nHere is the encrypted message: {}".format(alphabet, enc_msg))
signal.alarm(18)
resp = input("What is the plaintext message? ").rstrip()
if resp and resp == msg:
print("Congratulations! Here's the flag: {}".format(open("flag").read()))
# https://en.wikipedia.org/wiki/Playfair_cipher
$ nc mercury.picoctf.net 6057
Here is the alphabet: meiktp6yh4wxruavj9no13fb8d027c5glzsq
Here is the encrypted message: y7bcvefqecwfste224508y1ufb21ld
What is the plaintext message?
Solution:
ソースの一番下にヒントがある。
key を 5 * 5 の table に配置する
平文2文字毎に暗号化(置換)する
2文字とも table の同じ行にある場合,それぞれ右の文字を暗号文字として出力
2文字とも table の同じ列にある場合,それぞれ下の文字を暗号文字として出力
上記以外は,同じ行の文字と交換するが,列は対角とする。
key alphabet は table ではどうなっているか?
playfair.pyを改造していく
#alphabet = open("key").read().rstrip()
alphabet = "meiktp6yh4wxruavj9no13fb8d027c5glzsq"
m = generate_square(alphabet)
print(m)
実行結果
>python sol2_playfair.py
[['m', 'e', 'i', 'k', 't', 'p'], ['6', 'y', 'h', '4', 'w', 'x'], ['r', 'u', 'a', 'v', 'j', '9'], ['n', 'o', '1', '3', 'f', 'b'], ['8', 'd', '0', '2', '7', 'c'], ['5', 'g', 'l', 'z', 's', 'q']]
[['m', 'e', 'i', 'k', 't', 'p'],
['6', 'y', 'h', '4', 'w', 'x'],
['r', 'u', 'a', 'v', 'j', '9'],
['n', 'o', '1', '3', 'f', 'b'],
['8', 'd', '0', '2', '7', 'c'],
['5', 'g', 'l', 'z', 's', 'q']]
平文が 4wa1df とする
4w は同じ行にあるので wx に
aq は同じ列にあるので 10 に
df はそれ以外なので, 7o に(下図参照)
平文 4wa1d を暗号化すると wx107o になる。
暗号化の仕組みがわかったので,playfair.pyを改造したソルバーを完成させる
#!/usr/bin/python3 -u
import signal
SQUARE_SIZE = 6
def generate_square(alphabet):
assert len(alphabet) == pow(SQUARE_SIZE, 2)
matrix = []
for i, letter in enumerate(alphabet):
if i % SQUARE_SIZE == 0:
row = []
row.append(letter)
if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
matrix.append(row)
return matrix
def get_index(letter, matrix):
for row in range(SQUARE_SIZE):
for col in range(SQUARE_SIZE):
if matrix[row][col] == letter:
return (row, col)
print("letter not found in matrix.")
exit()
def encrypt_pair(pair, matrix):
p1 = get_index(pair[0], matrix)
p2 = get_index(pair[1], matrix)
if p1[0] == p2[0]:
# return matrix[p1[0]][(p1[1] + 1) % SQUARE_SIZE] + matrix[p2[0]][(p2[1] + 1) % SQUARE_SIZE]
return matrix[p1[0]][(p1[1] - 1) % SQUARE_SIZE] + matrix[p2[0]][(p2[1] - 1) % SQUARE_SIZE]
elif p1[1] == p2[1]:
# return matrix[(p1[0] + 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] + 1) % SQUARE_SIZE][p2[1]]
return matrix[(p1[0] - 1) % SQUARE_SIZE][p1[1]] + matrix[(p2[0] - 1) % SQUARE_SIZE][p2[1]]
else:
return matrix[p1[0]][p2[1]] + matrix[p2[0]][p1[1]]
def encrypt_string(s, matrix):
result = ""
if len(s) % 2 == 0:
plain = s
else:
plain = s + "meiktp6yh4wxruavj9no13fb8d027c5glzsq"[0]
for i in range(0, len(plain), 2):
result += encrypt_pair(plain[i:i + 2], matrix)
return result
#alphabet = open("key").read().rstrip()
alphabet = "meiktp6yh4wxruavj9no13fb8d027c5glzsq"
m = generate_square(alphabet)
print(m)
#msg = open("msg").read().rstrip()
msg = "y7bcvefqecwfste224508y1ufb21ld"
enc_msg = encrypt_string(msg, m)
print("key: {}\nenc: {}\nmsg: {}".format(alphabet, msg, enc_msg))
#print("Here is the alphabet: {}\nHere is the encrypted message: {}".format(alphabet, enc_msg))
#signal.alarm(18)
#resp = input("What is the plaintext message? ").rstrip()
#if resp and resp == msg:
# print("Congratulations! Here's the flag: {}".format(open("flag").read()))
# https://en.wikipedia.org/wiki/Playfair_cipher
実行結果
>python sol2_playfair.py
[['m', 'e', 'i', 'k', 't', 'p'], ['6', 'y', 'h', '4', 'w', 'x'], ['r', 'u', 'a', 'v', 'j', '9'], ['n', 'o', '1', '3', 'f', 'b'], ['8', 'd', '0', '2', '7', 'c'], ['5', 'g', 'l', 'z', 's', 'q']]
key: meiktp6yh4wxruavj9no13fb8d027c5glzsq
enc: y7bcvefqecwfste224508y1ufb21ld
msg: wd9bukbspdtj7skd3kl8d6oa3f03g0
nc すると
$ nc mercury.picoctf.net 6057
Here is the alphabet: meiktp6yh4wxruavj9no13fb8d027c5glzsq
Here is the encrypted message: y7bcvefqecwfste224508y1ufb21ld
What is the plaintext message? wd9bukbspdtj7skd3kl8d6oa3f03g0
Congratulations! Here's the flag: 消しました
Some Assembly Required 2
Category: Web Exploitation
Description:
http://mercury.picoctf.net:53929/index.html
Hints:
(None)
Solution:
Some Assembly Required 1と同じやり方で進める
xakgK\5cNs>n;jl90;9:mjn9m<0n9::0::881<00?>u\00\00
XOR Brute Force かましてみる
ちょっと崩れてるけど =k を除去すればビンゴ
gogo
picoCTF gogo を Ghidra で静的解析しようとしたが。。。
Milkslap
Category: Forensics
Description:
🥛
Hints:
Look at the problem category
Solution:
右クリックでは画像の保存が出来ない。
どんな仕掛け?
ソース見てみる
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=400" />
<title>🥛</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="image" class="center"></div>
<div id="foot" class="center">
<h1>MilkSlap!</h1>
Inspired by <a href="http://eelslap.com">http://eelslap.com</a> <br>
Credit to: <a href="https://github.com/boxmein">boxmein</a> for code inspiration.
</div>
<script src="script.js">
</script>
</body>
</html>
/* source: milkslap-milkslap.scss */
body {
margin: 0;
padding: 0;
overflow: hidden; }
a {
color: inherit; }
.center {
width: 1080px;
height: 720px;
margin: 0 auto; }
#image {
height: 720px;
margin-top: 5%;
margin-bottom: 20px;
background-image: url(concat_v.png);
background-position: 0 0; }
#foot {
margin-bottom: 5px;
color: #999999; }
#foot h1 {
font-family: serif;
font-weight: normal;
font-size: 1rem;
text-align: center; }
これか。
background-image: url(concat_v.png);
フィルムみたい
とにかく保存できたので,「青い空を見上げればいつもそこに白い猫」の出番
青色ビット0抽出に反応した
あとはビット抽出
ARMssembly 3
Category: Reverse Engineering
Description:
What integer does this program print with argument 2541039191? File: chall_3.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
Hints:
beep boop beep boop...
.arch armv8-a
.file "chall_3.c"
.text
.align 2
.global func1
.type func1, %function
func1:
stp x29, x30, [sp, -48]!
add x29, sp, 0
str w0, [x29, 28]
str wzr, [x29, 44]
b .L2
.L4:
ldr w0, [x29, 28]
and w0, w0, 1
cmp w0, 0
beq .L3
ldr w0, [x29, 44]
bl func2
str w0, [x29, 44]
.L3:
ldr w0, [x29, 28]
lsr w0, w0, 1
str w0, [x29, 28]
.L2:
ldr w0, [x29, 28]
cmp w0, 0
bne .L4
ldr w0, [x29, 44]
ldp x29, x30, [sp], 48
ret
.size func1, .-func1
.align 2
.global func2
.type func2, %function
func2:
sub sp, sp, #16
str w0, [sp, 12]
ldr w0, [sp, 12]
add w0, w0, 3
add sp, sp, 16
ret
.size func2, .-func2
.section .rodata
.align 3
.LC0:
.string "Result: %ld\n"
.text
.align 2
.global main
.type main, %function
main:
stp x29, x30, [sp, -48]!
add x29, sp, 0
str w0, [x29, 28]
str x1, [x29, 16]
ldr x0, [x29, 16]
add x0, x0, 8
ldr x0, [x0]
bl atoi
bl func1
str w0, [x29, 44]
adrp x0, .LC0
add x0, x0, :lo12:.LC0
ldr w1, [x29, 44]
bl printf
nop
ldp x29, x30, [sp], 48
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",@progbits
Solution:
beq bne
lsr
簡単に説明する // を見て
func1:
stp x29, x30, [sp, -48]!
add x29, sp, 0
str w0, [x29, 28] // [x29, 28]は引数
str wzr, [x29, 44] // [x29, 44]は戻り値(初期値0)
b .L2
.L4:
ldr w0, [x29, 28]
and w0, w0, 1 // 1 と and して
cmp w0, 0 // 0になったら終了方向
beq .L3
ldr w0, [x29, 44]
bl func2 // func2 内で +3
str w0, [x29, 44]
.L3:
ldr w0, [x29, 28]
lsr w0, w0, 1 // 入力値を右シフト
str w0, [x29, 28]
.L2:
ldr w0, [x29, 28]
cmp w0, 0
bne .L4
ldr w0, [x29, 44] // 戻り値
ldp x29, x30, [sp], 48
ret
.size func1, .-func1
.align 2
.global func2
.type func2, %function
func2:
sub sp, sp, #16
str w0, [sp, 12]
ldr w0, [sp, 12]
add w0, w0, 3 // +3
add sp, sp, 16
ret
.size func2, .-func2
.section .rodata
.align 3
ゼロになるまで右シフトするループの中で,戻り値を+3し続けている。
つまり,入力値を2進数にしてビット数 を 3倍してることになる。
>>> hex((len(bin(2541039191))-2)*3)
'0x60'
picoCTF{00000060}
Sorry, that flag is incorrect!
なんでだろ?
Compress and Attack
picoCTF Practice Compress and Attack Writeup
Disk, disk, sleuth! II
Super Serial
フラグは異なりますが,解き方は同じです。
picoCTF 2021 Super Serial
So Meta
なんで6ページ目にこんな簡単な問題があるのか意味不明だ。