{"id":206,"date":"2023-02-10T09:42:41","date_gmt":"2023-02-10T08:42:41","guid":{"rendered":"https:\/\/babdcatha.net\/?p=206"},"modified":"2023-02-10T11:52:04","modified_gmt":"2023-02-10T10:52:04","slug":"owasp-pixi","status":"publish","type":"post","link":"https:\/\/babdcatha.net\/index.php\/2023\/02\/10\/owasp-pixi\/","title":{"rendered":"OWASP : Pixi"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Hey, in this post we are going to look at a few of the (intentionally many) vulnerabilities present in the <a href=\"https:\/\/github.com\/DevSlop\/Pixi\">Pixi webapp<\/a>, created by the OWASP as a platform for people to learn what not to do when creating web applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a summary :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#broken_secret\">Broken secret<\/a><\/li>\n\n\n\n<li><a href=\"#reflected_xss\">Reflected XSS<\/a><\/li>\n\n\n\n<li><a href=\"#admin_bypass\">Admin page bypass<\/a><\/li>\n\n\n\n<li><a href=\"#CSRF\">CSRF to delete images<\/a><\/li>\n\n\n\n<li><a href=\"#decoding_JWT\">Decoding a JWT token<\/a><\/li>\n\n\n\n<li><a href=\"#dumping_any_password\">Dumping any password<\/a><\/li>\n\n\n\n<li>Giving anyone admin rights<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"broken_secret\">Broken secret<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When we create an account and login into the app, we are sent to the main page of the application :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-1\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"839\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/initiall_site-1024x839.png\" alt=\"\" class=\"wp-image-212\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/initiall_site-1024x839.png 1024w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/initiall_site-300x246.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/initiall_site-768x629.png 768w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/initiall_site.png 1152w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">On it, we see the expected menus, but one is out of the ordinary : Secret. When clicking on it, we get an error page :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-2\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"473\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_error_page.png\" alt=\"\" class=\"wp-image-213\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_error_page.png 962w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_error_page-300x148.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_error_page-768x378.png 768w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This error page is not caused by us not being authorized to see the secret page, but by a coding error from the developer. It tells us that &#8220;server.conf&#8221; is not a function. What is it then ? if we try to go to \/server.conf, we see this file :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-3\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"473\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_server_conf.png\" alt=\"\" class=\"wp-image-214\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_server_conf.png 962w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_server_conf-300x148.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/secret_server_conf-768x378.png 768w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And just like that, the secret used to create JWT tokens was leaked, meaning that we will now be able to create valid token for anything.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"reflected_xss\">Reflected XSS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The search page is vulnerable to XSS injections, meaning that we could create a malicious link to the website with our payload, send it to another user, and their browser would execute that payload. For example, visiting <a href=\"http:\/\/172.17.0.1:8000\/search\/?query=%3Cscript%3Ealert(%27hi%27)%3C\/script%3E\">http:\/\/172.17.0.1:8000\/search\/?query=%3Cscript%3Ealert(%27hi%27)%3C\/script%3E<\/a> gives us this :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-4\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"473\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/reflected_xss.png\" alt=\"\" class=\"wp-image-218\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/reflected_xss.png 962w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/reflected_xss-300x148.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/reflected_xss-768x378.png 768w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"admin_bypass\">Admin page bypass<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Enumerating the website gives us the existence of the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-primary-color\">\/admin<\/mark> page, which is probably an administration page. Since we don&#8217;t have admin rights on our account, trying to access this page returns us a json message indicating that we are not administrators :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-5\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"473\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_blicked.png\" alt=\"\" class=\"wp-image-249\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_blicked.png 962w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_blicked-300x148.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_blicked-768x378.png 768w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">However, this protection is poorly implemented, and only searches to match &#8220;admin&#8221;, this means that going to <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-primary-color\">\/Admin<\/mark> allows anyone to access the admin page :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-6\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"944\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_bypassed.png\" alt=\"\" class=\"wp-image-250\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_bypassed.png 962w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_bypassed-300x294.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/admin_bypassed-768x754.png 768w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"CSRF\">CSRF to delete images<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When we try to delete a photo we uploaded, we can see that a simple get request is made to <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-primary-color\">\/user_delete_photo\/image_id<\/mark>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-7\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"471\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_request.png\" alt=\"\" class=\"wp-image-222\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_request.png 960w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_request-300x147.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_request-768x377.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">However, when we try to delete an image that we do not own, we get an error, telling us that we do not own this image. What if someone posted a picture we don&#8217;t want online ? We could try to get them to send a request to this endpoint, and the photo would be deleted. Sending it directly would be too obvious. What we could do instead is host a webpage totally unrelated, and have one of the images have its source at <a href=\"http:\/\/172.17.0.1:8000\/user_delete_photo\/image_id\">http:\/\/172.17.0.1:8000\/user_delete_photo\/image_id<\/a>. When the victim visits this page, their browser would make a GET request to this URL, deleting the image. This is made really easy by the website, since photo ids are shown along with the image on the main page.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, imagine the user bbabb uploaded photo 221 that we wanted to delete.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-8\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"654\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_initial-1024x654.png\" alt=\"\" class=\"wp-image-224\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_initial-1024x654.png 1024w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_initial-300x192.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_initial-768x490.png 768w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_initial.png 1314w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a page we could create :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"markup\" class=\"language-markup\">&lt;p&gt;HTTP 418 : I'm a teapot&lt;\/p&gt;\n&lt;img src=\"http:\/\/172.17.0.1:8000\/user_delete_photo\/221\"&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We host it using a python server :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">python3 -m http.server 4445<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When the victim visits <a href=\"http:\/\/our_server\/page.html\">http:\/\/maliciousserver.com\/page.html<\/a>, this is what he sees :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-duotone-unset-9\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"473\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_page.png\" alt=\"\" class=\"wp-image-226\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_page.png 962w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_page-300x148.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_page-768x378.png 768w\" sizes=\"auto, (max-width: 962px) 100vw, 962px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">But, when he goes back to his images, image 221 is missing, and has been deleted :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-10\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"755\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_after-1024x755.png\" alt=\"\" class=\"wp-image-227\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_after-1024x755.png 1024w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_after-300x221.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_after-768x566.png 768w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/csrf_after.png 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This worked because Firefox sent the cookies for <a href=\"http:\/\/172.17.0.1\">http:\/\/172.17.0.1<\/a> when making the request. On Chromium, this attack did not work, because the request did not include these cookies.<\/p>\n\n\n\n<div class=\"wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-f56f613f wp-block-group-is-layout-flex\">\n<figure class=\"wp-block-image size-full is-resized wp-duotone-unset-11\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/firefox_cookies.png\" alt=\"\" class=\"wp-image-233\" width=\"315\" height=\"272\"\/><figcaption class=\"wp-element-caption\">request on Firefox<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full is-resized wp-duotone-unset-12\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/chromium_cookies.png\" alt=\"\" class=\"wp-image-234\" width=\"315\" height=\"272\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/chromium_cookies.png 631w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/chromium_cookies-300x259.png 300w\" sizes=\"auto, (max-width: 315px) 100vw, 315px\" \/><figcaption class=\"wp-element-caption\">request on Chromium<\/figcaption><\/figure>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"decoding_JWT\">Decoding a JWT token<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">On the main page, we are told that Pixi now has an API, running on port 8090, and we are given a link to its documentation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using this knowledge, we can create an account, and login on the API to get a JWT token :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-13\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"502\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/postman_login-1024x502.png\" alt=\"\" class=\"wp-image-241\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/postman_login-1024x502.png 1024w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/postman_login-300x147.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/postman_login-768x377.png 768w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/postman_login-1536x754.png 1536w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/postman_login.png 1920w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Since we know the JWT secret used (see <a href=\"#broken_secter\">here<\/a>), we can decode this token and see what it holds :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-14\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"704\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/jwt_decoded-1024x704.png\" alt=\"\" class=\"wp-image-243\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/jwt_decoded-1024x704.png 1024w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/jwt_decoded-300x206.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/jwt_decoded-768x528.png 768w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/jwt_decoded.png 1194w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We can see that a lot of information is stored on this token, a lot more that it should, which leads us to the next vulnerability.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"dumping_any_password\">Dumping any password<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If we look at the documentation for the API, we see an endpoint<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-primary-color\"> \/user\/info<\/mark> which allows a user to get his account information by sending his JWT token. We know what the JWT holds, but this endpoint probably uses only the id when fetching user data, this means that by creating a new JWT token with random data and the id of the user we want the info about, we can get his email and password :<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, using this payload in the JWT token :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"json\" class=\"language-json\">{\n  \"user\": {\n    \"_id\": 25,\n    \"email\": \"bbabb@aa.aa\",\n    \"password\": \"aaaa\",\n    \"name\": \"test\",\n    \"pic\": \"https:\/\/s3.amazonaws.com\/uifaces\/faces\/twitter\/themadray\/128.jpg\",\n    \"is_admin\": true,\n    \"account_balance\": 49.70000000000002,\n    \"all_pictures\": []\n  },\n  \"iat\": 1676024364\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We can dump user 25 :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large wp-duotone-unset-15\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"448\" src=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/dump_25-1024x448.png\" alt=\"\" class=\"wp-image-245\" srcset=\"https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/dump_25-1024x448.png 1024w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/dump_25-300x131.png 300w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/dump_25-768x336.png 768w, https:\/\/babdcatha.net\/wp-content\/uploads\/2023\/02\/dump_25.png 1505w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Hey, in this post we are going to look at a few of the (intentionally many) vulnerabilities present in the Pixi webapp, created by the OWASP as a platform for people to learn what not to do when creating web applications. Here is a summary : Broken secret When we create an account and login [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[4],"tags":[22,24,17,20,21,23],"class_list":["post-206","post","type-post","status-publish","format-standard","hentry","category-writeups","tag-api","tag-csrf","tag-nosql","tag-owasp","tag-pixi","tag-xss"],"featured_image_src":null,"author_info":{"display_name":"BabdCatha","author_link":"https:\/\/babdcatha.net\/index.php\/author\/admin4804\/"},"_links":{"self":[{"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/posts\/206","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/comments?post=206"}],"version-history":[{"count":27,"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/posts\/206\/revisions"}],"predecessor-version":[{"id":251,"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/posts\/206\/revisions\/251"}],"wp:attachment":[{"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/media?parent=206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/categories?post=206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/babdcatha.net\/index.php\/wp-json\/wp\/v2\/tags?post=206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}