Pragyan CTF writeup

周末打了ctftime上的比赛,记录一下

web

这题很无聊,cookie处flag直接解MD5,得到两个字符,抓包set-cookie处的flag解MD5得到两个字符,拼起来是pctf,将set-cookie处的flag发回去得到新的MD5,继续解MD5直到得到flag即可
cookie
提供一个很好用的解MD5的网站:https://www.somd5.com/

Game of Faces

看一下源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en" dir="ltr">

<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="index.css">
<meta charset="utf-8">
<title></title>
</head>

<body>
<div class="row">
<div class="col-lg-4" id="item1">
<div class="container">
<div class="form_img">\t <form action='#' method="GET" target="resultFrame"> Upload Your Profile Picture
: <input type="file" name="profile_pic"> <input type="submit" value="Upload Image"
name="submit"> </form>
</div>
</div>
</div>
<div class="col-lg-4" id="item2"> </div>
<div class="col-lg-4" id="item3"> </div>
</div>
<script type="text/javascript" src="index.js"></script>
<div class="row">
<div class="col-lg-12"> </div>
</div>
</body>

</html>

发现有一个GET方法,参数是profile_pic,随便提交点东西,得到一串base64
result-1
解码得到The_scroll_says=the_night_kingVSvalyrian.txt,访问即可得到flag
ps:这题纯脑洞,pure sh*t

Mandatory PHP

题目给出了源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php include 'flag.php';
highlight_file('index.php');
$a = $_GET["val1"];
$b = $_GET["val2"];
$c = $_GET["val3"];
$d = $_GET["val4"];
if (preg_match('/[^A-Za-z]/', $a)) {
die('oh my gawd...');
}

$a = hash("sha256", $a);
$a = (log10($a ** (0.5))) ** 2;
if ($c > 0 && $d > 0 && $d > $c && $a == $c * $c + $d * $d) {
$s1 = "true";
} else {
die("Bye...");
}

if ($s1 === "true") {
echo $flag1;
}

for ($i = 1; $i <= 10; $i++) {
if ($b == urldecode($b)) {
die('duck');
} else {
$b = urldecode($b);
}

}
if ($b === "WoAHh!") {
$s2 = "true";
} else {
die('oops..');
}

if ($s2 === "true") {
echo $flag2;
}

die('end...');

可以分析出需要提交四个参数,且满足$a == $c * $c + $d * $d
当val1传入字母时,经过hash("sha256",$a)(log10($a**(0.5)))**2后会得到INF
$a == $c * $c + $d * $d里是==,经过尝试,发现特别大的数==INF会返回true
php
所以可以构造如下payload绕过第一步判断
val1=a&val2=b&val3=8e99999999999999999999999999999999999999999&val4=9e99999999999999999999999999999999999999999
得到前半段flagpctf{b3_c4r3fu1_duck
再看后半段,发现只需要满足val2经过10次urldecode后等于WoAHh!即可

1
2
3
4
<?php
$b = "WoAHh!";
for ($i = 1; $i <= 10; $i++) {$b = urlencode($b);}
echo $b;

得到结果为WoAHh%25252525252525252521,将四个参数提交就可以得到flag
pctf{b3_c4r3fu1_w1th_pHp_f31145}

Forensics

welcome

首先得到一张图片,用foremost看一下,得到一个zip
zip
打开发现是一个加密的zip和secret.bmp,用010editor可以打开secret.bmp发现一串base64
dGhlIHBhc3N3b3JkIGlzOiBoMzExMF90aDNyMyE==,解码后得到the password is: h3110_th3r3!
打开加密的zip文件可以看到一张图片,用stegsolve打开,切换通道可以看到flag
flag

Magic PNGs

题目给了一张图片和一个加密的zip文件,无法直接查看图片,用010editor打开后发现文件头有问题
head
改成正确的文件头89 50 4E 47 0D 0A 1A 0A,保存后发现还是打不开,再看IDAT数据块,发现有问题
idat
改成正确的IDAT49 44 41 54,保存后就可以打开了
you_cant_see_me
根据提示将得到的h4CK3RM4n根据提示MD5就可以得到压缩包密码了,解开得到flag pctf{y0u_s33_m33_n0w!}

Late PR

给了一个特别大的文件,尝试用strings DELTAFORCE-PC-20190308-204453.raw | grep pctf找一下,结果直接出来了???
flag: pctf{Late_submissions_can_be_good}
下载3小时,做题3分钟?只能说这题pure sh*t

Save Earth

用wireshark打开发现是usb流量,尝试用tshark分离一下
tshark -r SaveEarth.pcap -T fields -e usb.capdata > usbdata.txt
得到了一组8字节的流量
usb
尝试用王一航师傅的脚本解一下,失败
这题真的服气,看了别人的writeup发现第二个字节提取出来24241214424144414444214442144422
然后转成摩斯电码-.-. - ..-. ... ....- ...- ...--.,解码后CTFS4V3
这脑洞我服了,只能说pure sh*t +1

Slow Realization

题目给了一个加密的pdf文件和一张图片,尝试用kali下的pdfcrack爆破一下,得到了密码
crack
解开pdf就得到了flagpctf{y0u_h34rd_m3_r1ght}

MISC

EXORcism

题目给了一个只有01的txt,看起来非常熟悉,推测是二维码的01,用脚本试试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# version = python 3.6
from PIL import Image

#去掉换行
e = open("encoded.txt", "r")
n = open("new.txt", "w")
r = e.read()
r = r.replace("\n","")
n.write(r)
e.close()
n.close()

#将01转成图片
img = Image.new('1', (100,100))
d = img.load()
f = open("new.txt","r")
data = f.read()
for n, i in enumerate(data):
d[(n % 100, n/100)] = int(i)*255
f = open('out.png', 'wb')
img.save(f)

得到的二维码扫描出一串160f15011d1b095339595138535f135613595e1a
根据题目猜测是异或,将flag作为key进行尝试

1
2
3
4
s = bytes.fromhex('160f15011d1b095339595138535f135613595e1a').decode("utf-8")
key = "flag"
decode = "".join(chr(ord(c1) ^ ord(c2)) for (c1, c2) in zip(s, key))
print(decode)

得到了pctf,将key换成flagflagflagflagflagflag就可以得到flagpctf{wh4_50_53r1u5?}

Cryptography

Spoiler

题目给了一个pdf文件,里面有一行意义不明的字符串,这里有个脑洞,把文件下载下来会在pdf文件后边看到一串字符
pdf
尝试解码
decode
尝试将两个字符串异或一下

1
2
3
4
s = "jonsnowisdragonbybirth"
key = bytes.fromhex('3a2c3a35152538272c2d213e332e3c25383030373a15').decode("utf-8")
decode = "".join(chr(ord(c1)^ord(c2)) for (c1,c2) in zip(s,key))
print(decode)

解得flagPCTF{JON_IS_TARGARYEN}

easy RSA

看到题目里的e非常大,想到RSA wiener attack,找个脚本试一下
解出了私钥d12978409760901509356642421072925801006324287746872153539187221529835976408177
然后常规RSA解密即可得到flagpctf{Sup3r_st4nd4rd_W31n3r_4tt4ck}

Help Rabin

题目给了三个文件,一个加密代码,一个公钥文件,以及密文文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import *
import random
def nextPrime(prim):
if isPrime(prim):
return prim
else:
return nextPrime(prim+1)

p = getPrime(512)
q = nextPrime(p+1)

while p%4 != 3 or q%4 !=3:
p = getPrime(512)
q = nextPrime(p+1)
n = p*q

m = open('secret.txt').read()
m = bytes_to_long(m)
m = m**e
c = (m*m)%n
c = long_to_bytes(c)
c = c.encode('hex')
cipherfile = open('ciphertext.txt','w')
cipherfile.write(c)

分析加密代码可以知道,p和q是两个连续的素数,密文为m^(2*e) mod n,此时我们并不知道n和e
根据题目的Rabin和代码生成p和q的方式,推测是Rabin密码体制,而Rabin密码体制是对RSA的修正,可以尝试用openssl来读取公钥
openssl
发现e等于1,证明确实是Rabin密码体制
将公钥的16进制转换成10进制

1
2
3
4
5
6
7
8
9
print(int('''61:5b:e0:98:72:7a:e6:10:de:9c:10:48:19:f3:a1: 
f7:cc:5b:31:44:81:0b:38:d4:f4:d5:1b:be:11:d9:
ca:20:f2:87:ee:d0:23:6b:ce:d1:fe:44:3a:33:5a:
2f:33:c7:a8:ac:68:f0:9f:c5:f3:8b:fe:37:4a:92:
07:d3:07:3d:40:2c:7a:65:a3:0b:60:f7:5b:10:e4:
3a:29:67:30:aa:22:d3:25:27:f7:20:3e:c9:be:cc:
6a:7a:0d:d7:0a:5c:e3:d1:d5:f2:a8:db:98:68:e8:
a4:53:4e:ef:70:5f:2c:6a:83:26:c8:8a:53:6b:82:
7c:88:bc:00:05:22:7a:c9'''.replace(" ","").replace("\n","").replace(":",""),16))

得到公钥n为68367741643352408657735068643514841659753216083862769094847066695306696933618090026602354837201210914348646470450259642887798188510482019698636160200778870456236361521880907328722252080005877088416283896813311117096542977573101128888124000494645965045855288082328139311932783360168599377647677632122110245577
脚本解密,感谢大佬的分享

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import gmpy2
from Crypto.Util.number import *

#openssl rsa -noout -text -inform PEM -in publickey.pem -pubin
n = 68367741643352408657735068643514841659753216083862769094847066695306696933618090026602354837201210914348646470450259642887798188510482019698636160200778870456236361521880907328722252080005877088416283896813311117096542977573101128888124000494645965045855288082328139311932783360168599377647677632122110245577
sq,b = gmpy2.iroot(n,2)
while n%sq != 0:
sq += 1
p = sq
q = n / sq

with open("ciphertext.txt") as f:
ct = f.read()
ct = ct.decode('hex')
ct = bytes_to_long(ct)

q = int(q)
p = int(p)
assert(p * q == n)

mp = pow(ct, (p+1)/4, p)
mq = pow(ct, (q+1)/4, q)

from rsasim.gcd_utils import xgcd
g, yp, yq = xgcd(p, q)

r = (yp*p*mq + yq*q*mp) % n
mr = n - r
s = (yp*p*mq - yq*q*mp) % n
ms = n - s
for num in [r,mr,s,ms]:
print(long_to_bytes(num))

其中一组得到Hey Rabin, would you like to be the front end to my back end? Here is your flag: pctf{R4b1n_1s_th3_cut3st}

Decode This

题目给了加密代码和密文,首先分析一下加密代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import random

file = open("secret.txt","r")
secret = file.read()

flag = ""
for i in secret:
if i.isalpha():
flag += i
l = len(flag)

key = [[int(random.random()*10000) for e in range(2)] for e in range(2)]

i = 0
ciphertext = ""

while i <= (l-2):
x = ord(flag[i]) - 97
y = ord(flag[i+1]) - 97
z = (x*key[0][0] + y*key[0][1])%26 + 97
w = (x*key[1][0] + y*key[1][1])%26 + 97
ciphertext = ciphertext + chr(z) + chr(w)
i = i+2

cipherfile = open('ciphertext.txt','w')
cipherfile.write(ciphertext)

根据代码我们可以知道flag都是小写字母,key是一个2x2的数组且无法爆破,密文是两个两个一组的,明文里边有pctf,应该是二维hill密码的已知明文攻击
由于我们不知道pctf的位置,所以只能选择爆破,这里选择用sagemath
脚本来Kaushik S Kalmady

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env sage -python

import binascii
from sage.all import *

R = IntegerModRing(26)

def solve(inputs, res):
M = Matrix(R, inputs)
b = vector(R, res)
return M.solve_right(b)

def verifyflag(c, key):
#print "Verifying"
i = 0
l = len(c)
ans = ""
while i <= (l - 2):
z = ord(c[i]) - 97
w = ord(c[i+1]) - 97

res = [z, w]
try:
c1, c2 = solve(key, res)
ans = ans + chr(int(c1) + 97) + chr(int(c2)+ 97)
i += 2

except:
print "Couldn't Solve"
return False

print ans
return True

运行结果
findout
得到flag pctf{ilikeclimbinghillswhataboutyou}

0%