cit*_*ane 7 c casting function-pointers void shellcode
我正在查看来自不安全编程的示例abo3.c,并且我没有在下面的示例中讨论转换.有人可以开导我吗?
int main(int argv,char **argc)
{
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system;
char buf[256];
fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
fn(argc[2]);
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
那么 - 系统的投射和投注是什么?他们都回归了int
,为什么要把它变成无效?
我非常感谢对整个计划的解释.
[编辑]
感谢您的投入!
Jonathan Leffler,实际上代码有"坏"的原因.它应该是可利用的,溢出缓冲区和函数指针等.mishou.org有一篇关于如何利用上述代码的博客文章.其中很多仍然在我头上.
bta,我从上面的博客文章中得知,转换系统会以某种方式阻止链接器删除它.
有一点不能立即明确的是系统和放置地址都写在同一个位置,我想这可能是gera所说的"所以链接器不会删除它".
虽然我们讨论的是函数指针的主题,但现在我想问一个后续问题,即语法更清晰.我正在使用函数指针查看一些更高级的示例,并偶然发现这个可憎的东西,取自托管shellcode的站点.
#include <stdio.h> char shellcode[] = "some shellcode"; int main(void) { fprintf(stdout,"Length: %d\n",strlen(shellcode)); (*(void(*)()) shellcode)(); }
所以数组被强制转换为函数返回void
,引用和调用?这看起来很讨厌 - 所以上面代码的目的是什么?
[/编辑]
Jon*_*ler 10
用户bta给出了演员的正确解释 - 并评论了演员的不合理性system
.
我要补充一下:
这extern
条线充其量是怪异的.在严格的C99下它是错误的,因为没有类型,这使它无效; 根据C89,类型将被假定为int
.该行说'有一个外部定义的整数称为系统,另一个称为puts',这是不正确的 - 有一对带有这些名称的函数.代码实际上可能"有效",因为链接器可能会将函数与假定的整数相关联.但对于指针尺寸不同的64位机器来说,这是不安全的int
.当然,代码应该包含正确的标题(<stdio.h>
for puts()
和<stdlib.h>
for system()
和exit()
,以及<string.h>
for strcpy()
).
该exit(1);
是两个独立的罪名坏.
它表示失败 - 无条件.您以0退出或EXIT_SUCCESS
表示成功.
在我看来,它是更好地使用return
在年底main()
比exit()
.不是每个人都必须同意我,但我不喜欢看到exit()
最后一行main()
.关于它的唯一借口是避免其他不良做法的问题,例如注册的函数atexit()
取决于中定义的局部变量的继续存在main()
.
/usr/bin/gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -c nasty.c
nasty.c: In function ‘main’:
nasty.c:3: warning: type defaults to ‘int’ in declaration of ‘system’
nasty.c:3: warning: type defaults to ‘int’ in declaration of ‘puts’
nasty.c:3: warning: built-in function ‘puts’ declared as non-function
nasty.c:8: warning: implicit declaration of function ‘strcpy’
nasty.c:8: warning: incompatible implicit declaration of built-in function ‘strcpy’
nasty.c:10: warning: implicit declaration of function ‘exit’
nasty.c:10: warning: incompatible implicit declaration of built-in function ‘exit’
nasty.c: At top level:
nasty.c:1: warning: unused parameter ‘argv’
Run Code Online (Sandbox Code Playgroud)
不好的代码!我担心包含这些代码的信息来源并不能解释所有可怕的问题(因为显示这种混乱代码的唯一借口是剖析它并纠正它).
代码中还有另一个奇怪之处:
int main(int argv,char **argc)
Run Code Online (Sandbox Code Playgroud)
这是'正确'(它会起作用),但100%是常规的.正常的声明是:
int main(int argc, char **argv)
Run Code Online (Sandbox Code Playgroud)
名称是'参数计数'和'参数向量'的缩写,并且使用argc
字符串的向量(数组)作为名称是异常和彻头彻尾的混淆.
访问过引用的站点后,您可以看到它正在通过一组分级示例.我不确定作者是否只是对argc/argv问题有一个盲点,或者是故意搞乱('abo1'表示他正在玩,但在我看来这没有帮助).这些例子可以满足你的想法,但对他们所做的事情没有多少解释.我认为我不能推荐这个网站.
这段代码中的演员是做什么的?
#include <stdio.h>
char shellcode[] = "some shellcode";
int main(void)
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
}
Run Code Online (Sandbox Code Playgroud)
这需要字符串"的shellcode"的地址,并把它当作一个指针,它接受一个不确定组参数和返回值不和不带参数执行它的功能.该字符串包含用于某些漏洞利用的二进制汇编程序代码 - 通常运行shell - 入侵者的目标是获取root权限程序来执行其shellcode并为其提供具有root权限的命令提示符.从那里,系统是他们拥有的.对于练习,第一步是获得一个非root程序来执行shellcode,当然.
米首网站上的分析并不像我想的那样具有权威性:
一,此代码使用C语言中的extern关键字来使系统和函数可用.这个(我认为)基本上是直接引用(隐含的)头文件中定义的函数的位置...我得到的印象是GDB自动神奇地包括用于系统的头文件stdlib.h和用于puts的stdio.h .有一点不能立即明确的是系统和放置地址都写在同一个位置,我想这可能是gera所说的"所以链接器不会删除它".
剖析评论:
system
并puts
在其他地方定义(作为整数).链接代码时,puts()
-the-function 的地址是已知的; 代码将它视为整数变量,但整数变量的地址实际上是函数的地址 - 因此强制转换强制编译器将其视为函数指针.system()
和puts()
C库解析外部"变量"的地址.这并没有激励我阅读整篇文章,必须说.尽职调查迫使我前进; 之后的解释更好,但仍然没有我想象的那么清楚.但是,使用超长但精心设计的参数字符串溢出缓冲区的操作是该操作的核心.代码提到了两者puts()
,system()
因此当在非漏洞利用模式下运行时,该puts()
函数是一个已知符号(否则,您必须使用它dlopen()
来查找其地址),因此当在漏洞利用模式下运行时,代码具有符号system()
可直接使用.可执行文件中没有未使用的外部引用 - 当您意识到典型系统头中有多少符号与包含头文件的程序所使用的编号相比时,这是一件好事.
显示了一些巧妙的技巧 - 尽管特定页面上没有显示这些技巧的实现; 我假设(未经验证)getenvaddr
程序信息可用.
abo3.c代码可以写成:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
void (*fn)(char*) = (void(*)(char*))system;
char buf[256];
fn = (void(*)(char*))puts;
strcpy(buf, argv[1]);
fn(argv[2]);
exit(1);
}
Run Code Online (Sandbox Code Playgroud)
现在它只使用我最初使用的繁琐的编译选项编译了一个警告 - 这就是没有使用'argc'的准确警告.它和原版一样可以利用; 它是"更好"的代码,因为它编译得很干净.间接是不必要的神秘,而不是使代码可利用的关键部分.