TFTP Protocol Overview
TFTP AKA Trivial File Transfer Protocol is a simple protocol being used for network file transfer, TFTP protocol is implemented on top of the user Datagram Protocol (UDP) and uses DGRAM socket in your Python code, and uses port 69 by default, and of course, change that port of your choice. TFTP is based on the client/server principle. However, it does not support authentication and has no list of directory contents. Since it uses UDP it’s not commonly used over the internet but more likely used on internal/local networks.
How TFTP Works?
There are four types of TFTP Messages which are as follows:
Read Request –> Opcode (1)
Write Request –>Opcode (2)
Data Message –> Opcode (3)
Acknowledgement Message –> Opcode (4)
Error Message –> Opcode (5)
Acknowledge of data: TFTP only uses positive acknowledgements (correctly received packets are acknowledged with an ACK packet). When the sender does not receive an ACK packet in due time, it re-sends the last DATA packet.
Transfer Mode: The string “netascii” or “octet”, zero-terminated.
In TFTP, the file is divided into different blocks of data consisting of 512 bytes, except for the last block. The last block is identified by its size of less than 512 bytes.
If any Block of data is lost during transfer, the TFTP Client will not send the acknowledgment message. so, a timeout will happen at the TFTP Server, and the lost TFTP DATA packet is sent again.
1- Coping file from TFTP Server to TFTP Client sending TFTP RRQ (Read Request) message packet to the TFTP server. Remember The Opcode for the RRQ message is (1) and the WRQ message is 2. The Mode (Type) of transfer for text files is netascii.
2- TFTP RRQ (Read Request) message is received to copy a file, TFTP server will reply back either with the first Block of data or with a TFTP ERROR message. In case everything is fine then it will reply is with the first block of data (512 bytes).
File transfer is made by slicing the file into blocks send by order to TFTP Client, and then TFTP Client acknowledges each Block of data by replying with a TFTP ACK message packet.
Note that the last Block of Data is identified by its file size, which is less than 512 bytes. Here is an example of an Opcode of error message.
So let’s exploit TFTP.
Exploit TFTP Serva & Pinkie
The main focus here is to exploit Read to write requests and check if they are vulnerable to buffer overflow or not. We can use any of the available fuzzers to test many cases such as backfuzz- fuzzowski.
In our case of Pinkie 2.15 and Serva 4.4.0, there was vulnerability to buffer overflow Read request Opcode (1) as we see in the following image.
Let’s ‘build our script
As we see we have imported socket module a, and then used DGRAM which handles the UDP connections. Also, we have created the read request with Opcode (1) in line 12 and so send (b) or (a) 32768 times and also mention the transfer mode (netascii) and finally the IP and the port.
Results Pinkie TFTP crashed – Not all buffer overflows can lead to remote code execution. The same script can be used to crash Serva
But let’s create a Metasploit auxiliary for the denial of service, for Metasploit lovers.
As we see we mention the metasploit class type auxiliary, Remote UDP protocol, and type in DOS. Then we created a function that has the required information about the module like version name, Author, Disclosure date, and finally the register option which is the port number (69).
Another function that mentions the protocol name, then same mention the Opcode (1) which is the read request, and transfer mode (netascii).
We put the file on that path /pro/vendor/bundle/ruby/2.7.0/gems/metasploit-framework-6.1.5/modules/auxiliary/dos/windows/tftp and then open metasploit and run
We got a Serva crashed but let’s see the buffer inside the Olly debugger or run the program inside the debugger
Ops we got Anti debugger detection being implemented let’s bypass that. So we load the program again without running it and then Right click Search for All Referenced text strings. We search for debugger text until we hit the text that appeared to us (running Serva under a debugger is not allowed) then we double click on that.
As we see in the above image we found out the (IsDebuggerPresent) API checks if the current process is being debugged by a user-mode debugger. More Info on API. For Example
cmp eax, 1
Je _debugger_detected if eax==1 a Debugger has been detected
So we have stepped into the (IsDebuggerPresent) API as we see
MOV EAX,DWORD PTR FS:  is going to get/move EAX the address of thread environment block if you EAX follow in dump you will see some structures.
MOV EAX,DWORD PTR DS:[EAX+30] : get address of PEB structure. Is going to move to EAX the value of this located address + 30 HEX.
Movzx eax, byte ptr ds: [eax+2] get value of PEB.BeingDebugged. The third byte –> is being debugged is set to (1) if the process is being debugged.
As we see in the above image, when we step over this location and then EAX follow in dump we will see the byte is set to (1) so we going to change (7FFD8000 00010000) this back. Right Click Binary Edit and change from (1) to (0)
The reason we do that is to change to 0 because we don’t know how many times the program will check if it’s being debugged through that API and we have to locate all of them but instead modify the value inside the windows structure PEB
As we can see EAX = (0) and the jump will be taken to that address passing the message box of debugger has been detected. Of course, if EAX == 1 the jump will not be executed and the message will appear. In some cases, the value can be seen when you load the program, if you load Serva in Olly and just EBX follows in dump and changes to (0) and then run.
As we see Serva TFTP has been loaded inside the debugger and can run our script.
As we see we got stack buffer overflow that lead to denial of service aka crash. I got 2 CVE ( CVE-2021-44429) & (CVE-2021-44428) you can find the exploit codes here
Pinkie 2.15 – TFTP Remote Buffer Overflow & Serva 4.4.0 TFTP I hope enjoy the reading Mrvar0x