aboutsummaryrefslogtreecommitdiff
path: root/README
blob: db08afe31d085665d390e70838f426d8a1f1bb6d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
               _     _                _
              | |   | |              | |
              | |__ | |_   _  ___  __| |_ __ ___  __ _ _ __ ___
              | '_ \| | | | |/ _ \/ _` | '__/ _ \/ _` | '_ ` _ \
              | |_) | | |_| |  __/ (_| | | |  __/ (_| | | | | | |
              |_.__/|_|\__,_|\___|\__,_|_|  \___|\__,_|_| |_| |_|

================================================================================
  
         i went on a [47d1] and all i got was this lousy vscode worm...

                                     (or)

         i tried to write a README and all i got was this lousy writeup

  NOTE: some of this writeup had to be redacted for, uh, reasons. any redactions
        will be replaced with a relevant sha256 tag, which will be expanded at
        the end of the file. example: [480b2b30]

  INTRO
        late one night, i had an idea. 'memba xcodeghost? pepperidge farm
      remembers. what about vscodeghost? except, instead of infecting *OS apps,
      it infects vscode. hmm?

        it's a vscode worm. alice installs an infected extension, and any
      extensions (packaged or minified) become infected. once uploaded to the
      marketplace, or otherwise distributed, each install becomes a new alice.

        i will readily admit that i [084a1631cd59ed1a3244305b6fbc28a2d93c97a7df]

        this worm was written over the course of a 3-week [47d1] in which i
      [e6400ef383e6509261b52d3f16e466752487a27e19d0579a3eb5567bb7244055]. lmao

        it was bad... [e2b5ed016720f26e10bc200c8c528241298f9a64db8559b9ad8276b8]
      shit. [affa8bd6c29038c52a423488d1b037615d7bb8a8384736d46837c662887303f]...
      i know i gotta sleep in a few hours. welp. note from future spv: you're a
      dick. it's half past 2 and i'm copy editing your shit. fuck you. <3

        with that out of the way, let's begin with the writeup & description. i
      think the only real way to do this is to go through the architecture
      first. otherwise idk that any of this will make sense. it took me a couple
      readthroughs of the source to understand what the fuck was going on...

  ARCHITECTURE
        bluedream is made up of two interlinked components, with separate
      directories for each. cnc holds the command-and-control server, with inf
      containing the src for the local infection, and its custom build system.
      these components will be referred to by their respective directory names,
      cnc, and inf.

        inf is built by build_payload.js & gen_pwnage.js. build_payload is
      passed a payload descriptor (pd) file, which contains a reference to each
      JS file to be included. this allows one to easily configure of the exact
      features of a payload. build_payload also requires the specification of an
      output file, to which the payload, minified & brotli compressed, will be
      written.

        after this, gen_pwnage wraps the payload. to ease identification of the
      infection, as will be described in detail further on. in the end, one will
      be left with inf.

        cnc is also a custom job. cnc accepts a block descriptor (bd) file,
      which is used to serve different payloads to different victims. a bd file
      is composed of one or more entries of the form
      `(ip)[/(block_size)]:(payload)[,(script)]`. any ip within said block will
      be served the payload specified, with the script (if) specified being ran
      upon each serving.

        with the basics of bluedream's architecture covered, let's get into the
      nitty-griddy details of what makes her tick.
    
  TICK TICK TICK
        inf runs every time an infected extension is triggered, often at
      startup. upon being triggered, inf phones home to cnc at most once a day,
      which provides an updated copy of inf. after this, it spreads to any files
      in the workspace which contain (compiled) extension code. following this,
      inf spreads to all other currently installed extensions, in case the
      original vector is removed. lastly, inf will spread to any packaged
      extensions in the current workspace.

        in the following sections, we will discuss in (potentially excruciating)
      detail, how each of these vectors of spread work.
    
  SENTINELS
        the packaged infection is stored within extensions. much like a
      biological virus, it needs a host. to separate inf from the legitimate
      code, two markers are used. the specifics do not matter, but my commie ass
      used /*瑲慮猠*/ and /*物杨瑳*/. these are entirely gibberish Chinese characters.

        however, pipe them into a hex dump, and they are -- still garbage.
      codepoints, though? U+7472, U+616E, etc. interesting. interpret UTF-16 as
      ASCII, and they spell out "trans rights" :P

  THE MINI
        extensions are fun things. while you may write your neat and clean
      typescript, at the end of the day, it's javascript all the way down... and
      because we decided to take a technology hacked together in under two weeks
      and use it to power the entire fucking internet and most user-facing
      applications, we developed minification. even then, discord takes up
      ~100MB because it's its own damned chromium install... i fucking hate
      javascript.

        minification also provides some convenience for malware developers, like
      us. several megabyte, one line, obfuscated javascript isn't "a major cause
      for concern", it's just "webpack"! yay!

        we pick a spot to insert inf. either between two lines of typescript
      boilerplate, in a known location for webpack, or just at the end. this
      procedure is used to infect all extensions -- including local output
      files, as in `extension_js_spread`, local extension persistence as in
      `extension_spread`, and packaged extensions as in `vsix_spread`. what is a
      vsix, anyway?

  WHAT IS A VSIX, ANYWAY?
        vscode uses the vsix format to package extensions. vsix is, in essence,
      a glorified zip file. the relevant files for this writeup being
      extension.vsixmanifest, extension/package.json*, and
      extension/out/extension.js*.

        a vsixmanifest is an XML-formatted file that is, (i believe), used in
      both visual studio, and vscode. the relevant key in this file is
      "Microsoft.VisualStudio.Code.Manifest", which points at the package.json.

        within package.json, the key "main" points at the javascript code ran
      when the extension is triggered. with this knowledge, we are able to use
      the procedure described in THE MINI in order to pwn packaged extensions.
      the only difference being that we need logic to process zip files. the
      relevant code is in inf/mal/spread/vsix.js. this is a combination of YAZL,
      and an utterly nightmarish artisan-rolled zip file parser that to cope
      with imma need some artisan-rolled shit of my own...

        *these are the file names by convention. they do not technically have to
      be present at these particular locations.

  CONCLUSION(s)
        what would have stopped this attack from working? for one, signing
      vscode extensions upon packaging would have helped. vsce, the main tool
      used to package (, and often publish) vscode extensions, has had a github
      issue for this very topic since july of 2017. vscode never implemented
      support, though. [vsce_issue]

        i recall reading that extensions are signed upon being uploaded to the
      marketplace, but this would not prevent this attack, as extensions are
      already pwned by the time they're sent to the marketplace.

        and lastly, you are not an APT. sorry. this worm was written over the
      course of a 3 week [47d1] -- a coping mechanism after some interpersonal
      termoil, in which i experienced such delusions of grandeur that i
      genuinely believed that this worm was my golden ticket -- that i would be
      set for life, money wise. this is of course, utterly laughable. i threw
      away the plan immediately after deployment anyway, as i had recently
      [82821f1ccb55943a67b2d7689e08f7c6e548d3778b0835d2d0eebaf43c81e2bd], and i
      proceeded to [1c747f5c1eac42e9eb77c538a4f77b3b4c18b0bd8ce62dc88637e585a2].

                                   SHA_TAGS
                                  ==========
        084a1631cd59ed1a3244305b6fbc28a2d93c97a7df8dc117c90955a728b00d35
        1c747f5c1eac42e9eb77c538a4f77b3b4c18b0bd8ce62dc88637e585a2701298
        47d140cbea401190e9612d5c7e3bd78a5fbb63def20832036a1b2c4fbbac636b
        480b2b30b0c14c30d3f130561a44c77cba580910d2789593e4e379c2d26bc3f8
        82821f1ccb55943a67b2d7689e08f7c6e548d3778b0835d2d0eebaf43c81e2bd
        affa8bd6c29038c52a423488d1b037615d7bb8a8384736d46837c662887303f9
        e2b5ed016720f26e10bc200c8c528241298f9a64db8559b9ad8276b859a660ac
        e6400ef383e6509261b52d3f16e466752487a27e19d0579a3eb5567bb7244055


      OG: 6628738fac546ec9cf6193e2b3ab753e11f62f4fff8348ee4e0f499e00167210

                                     LINKS
                                    =======
         vsce_issue: https://github.com/Microsoft/vscode-vsce/issues/191

                                 ~ spv, 2025.