如何从外面更改argv [0]?

时间:2017-01-16 13:49:51

标签: c format-string

我有这样的C代码:

#include <stdio.h>

void x(int argc, char** argv) {
  printf(argv[0]);
}

int main(int argc, char** argv) {
  char* secret = "SECRET";

  if (argc < 2)
    x(argc, argv);
}

我现在想做一个格式字符串攻击来打印shell的秘密。但是,我不知道如何获取我想要argv [0]的字符串以及如何从另一个范围访问数据(因为从x开始,它不可能直接解决指针秘密。

我该怎么做?

2 个答案:

答案 0 :(得分:6)

在unix中,程序以execve(或其中一个包装器,例如execlp)启动。所有exec*函数都允许您传递argv的任意字符串,包括argv[0]

如果您是从shell以交互方式执行此操作,请查看内置的exec

( exec -a '%x...' ./prog )

parens创建子shell,exec加载并运行./prog到子shell进程中,-a的参数用作argv[0]

至于如何访问变量,请查看生成的汇编代码。如果secret存储在堆栈中并且printf从堆栈中提取参数,则可以通过指定足够的%x指令(后跟%s来获得所需的结果})。

答案 1 :(得分:3)

argv[0]包含程序名称,通常是您调用程序的字符串。对于使用./a.out执行的程序,argv[0]将指向./a.out

您的格式字符串攻击需要修改argv[0]。这意味着您需要将可执行文件重命名为符合您需要的格式字符串。

我将您的程序更改为从argv[1]读取并删除了argc < 2限制。在%s打印之前,我使用了%d并添加了"SECRET"。为什么%d?我认为堆栈与int的倍数(%d打印)对齐,因为sizeof(int)通常是自然字大小。

最后,我想出了%d%d%d%d%d%d%d%d%d%d%d%d%s。这会从堆栈中打印一些值(如果有某种“跳过”格式化程序以避免实际打印这些值,我会使用它),弹出这些值,最后打印"SECRET"

请注意,这是未定义的行为,完全取决于您的计算机。