A May 24th 2023 change of GitHub’s RSA SSH host key just hit me on an older, less used, system doing a git clone. The change was prompted by an unintended exposure of the private part of the host key by GitHub itself.
GitHub.com’s RSA SSH private key was briefly exposed in a public GitHub repository Github blog-post, “We updated our RSA SSH host key”, 2023-03-23
GitHub.com’s RSA SSH private key was briefly exposed in a public GitHub repository
I’m getting even more reluctant to trust a large organization where such a thing can happen. Additionally they didn’t communicate about this in a way that caught my attention. And now that it has my attention, they do not want to share the specifics about the incident to enable assessment of impact (like exposure duration, popularity of repository etc).
Below is the manual recovery with explanations of what happens and why. I don’t like the way the official blog-post instructs users to retrieving the validated host key in a non-visible way, without human eye balls doing the validation. This is the only chance in the process for injecting human trust into the validation of the host key, don’t skip it!
Consequence #1: fatal MitM warningWhen an SSH server’s host key is different to a connecting client (system) compared to what the system has previously seen and acknowledged by the user to be a valid key from the intended counterpart (you do check those host key fingerprint strings, right? If not; PHComp help, WinSCP help), it obviously should and do warn the user about this. Whether the change is of malicious origin or not, is up to the user to investigate. So with OpenSSH this happens;
$ git clone git@github.com:mikini/name-suggestion-index Cloning into 'name-suggestion-index'... @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the RSA key sent by the remote host is SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s. Please contact your system administrator. Add correct host key in <~>/.ssh/known_hosts to get rid of this message. Offending RSA key in <~>/.ssh/known_hosts:17 remove with: ssh-keygen -f "<~>/.ssh/known_hosts" -R "github.com" RSA host key for github.com has changed and you have requested strict checking. Host key verification failed. fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. $
Remedy #1: remove known host keys for domain (pr. OpenSSH instruction)Remove host keys associated with github.com domain using -R option to ssh-keygen (default for -f is the UserKnownHostsFile config keyword with default ~/.ssh/known_hosts, so no need to specify that):
$ ssh-keygen -R github.com# Host github.com found: line 17# Host github.com found: line 18# Host github.com found: line 19<~>/.ssh/known_hosts updated.Original contents retained as <~>/.ssh/known_hosts.old$Consequence #2: non-fatal domain and IP mismatchNow, because host key references are cached for both the domain and IP there are still mismatches caused by the key exchange choosing ECDSA host key and the key associated with the IP address is the old RSA key. This is prompted during each connection attempt:
$ git clone git@github.com:mikini/name-suggestion-index Cloning into 'name-suggestion-index'... Warning: the ECDSA host key for 'github.com' differs from the key for the IP address '140.82.121.3' Offending key for IP in <~>/.ssh/known_hosts:63 Matching host key in <~>/.ssh/known_hosts:72 Are you sure you want to continue connecting (yes/no)? yes remote: Enumerating objects: 153255, done. remote: Counting objects: 100% (177/177), done. remote: Compressing objects: 100% (103/103), done. remote: Total 153255 (delta 103), reused 121 (delta 74), pack-reused 153078 Receiving objects: 100% (153255/153255), 550.17 MiB | 2.39 MiB/s, done. Resolving deltas: 100% (111423/111423), done. $
Remedy #2: remove known host keys for IPsTo get rid of the mismatch warning, the known host keys associated with IP addresses needs to be removed also. Potentially any of the listed endpoint IP addresses used with an RSA host key on the system earlier will now conflict with the ECDSA from server, requiring removal:
$ ssh-keygen -R 140.82.121.3 # Host 140.82.121.3 found: line 63 <~>/.ssh/known_hosts updated. Original contents retained as <~>/.ssh/known_hosts.old $ $ ssh-keygen -R 140.82.121.4 # Host 140.82.121.4 found: line 161 <~>/.ssh/known_hosts updated. Original contents retained as <~>/.ssh/known_hosts.old $ After remedy Now, the SSH client will see an unknown host key and prompt for validation. Be sure to verify the presented host key with the officially communicated one (from doc. article or API):
$ git clone git@github.com:mikini/name-suggestion-index Cloning into 'name-suggestion-index'... The authenticity of host 'github.com (140.82.121.4)' can't be established. ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'github.com,140.82.121.4' (ECDSA) to the list of known hosts. remote: Enumerating objects: 153152, done. remote: Counting objects: 100% (183/183), done. remote: Compressing objects: 100% (83/83), done. Receiving objects: 100% (153152/153152), 550.22 MiB | 1.42 MiB/s, done. remote: Total 153152 (delta 109), reused 158 (delta 100), pack-reused 152969 Resolving deltas: 100% (111352/111352), done. $
Inspired by a John Sullivan (of FSF) tweet asking about opinions on the new and shiny MS(TM) GitHub(TM) CLI(TM) tool named “gh”(TM) I wanted to try it out on one of my Ubuntu LTS systems (16.04).
I’ve always disliked the proprietary and centralised monoculture of github, especially after that thing with MS, so I’ve mostly avoided using the service for code I produce myself. If interested in independence and decentralisation maybe you should read up on that long fabled subject? Thus I’ve never even tried the predecessor “hub”(TM) tool (main page), and exactly how it differs from this new “CLI” thing is not obviously apparent from the communications.
Nevertheless, the “gh” tool, officially dubbed GitHub CLI, being distributed under MIT license and written in go(lang) (afterwards, found out that this is indeed also applicable to the predecessing “hub” tool) made me curious enough to go see what they’re up to. Maybe its not that sinister a plot and they really just want to improve the independent and freely available mechanisms for source code storage, distribution and maintenance (I wish)?
A fairly recent (2019-09) version of go, >=1.13, is required so some gymnastics are needed to make stuff work on older distros like Ubuntu’s LTS (with 5 years support from Canonical). Anyway, this is what I did to build a useable “gh” ELF executable (20 MiB!, se below), this is from source, no precompiled stuff, no snaps. It was done on Ubuntu 16.04 (xenial) but I’ve been somewhat careful to inspect that things ought to be good for 18.04 (bionic) too. Non-essential output from the commands is largely discarded here. See Gory Details section below for the full monty.
$ sudo add-apt-repository ppa:longsleep/golang-backports $ sudo apt update $ sudo apt install golang $ go version go version go1.13.4 linux/amd64
$ cd $ git clone https://github.com/cli/cli .githubcli $ cd .githubcli $ make
$ echo 'export PATH="$HOME/.githubcli/bin:$PATH"' >> ~/.bash_profile $ bash --login $ gh Work seamlessly with GitHub from the command line. GitHub CLI is in early stages of development, and we'd love to hear your feedback at <https://forms.gle/umxd3h31c7aMQFKG7> Usage: gh [command] Available Commands: help Help about any command issue Create and view issues pr Create, view, and checkout pull requests repo Create, clone, fork, and view repositories Flags: --help Show help for command -R, --repo OWNER/REPO Select another repository using the OWNER/REPO format --version Show gh version Use "gh [command] --help" for more information about a command. subcommand is required $
Randomly picked one of my few github repos, it contains some js experiments on parsing NMEA formatted coordinates, rather uninterestingly empty.
user@host:~$ gh repo clone mikini/coordinates Notice: authentication required Press Enter to open github.com in your browser... <auth session in browser> Authentication complete. Press Enter to continue... Cloning into 'coordinates'... remote: Enumerating objects: 10, done. remote: Total 10 (delta 0), reused 0 (delta 0), pack-reused 10 Unpacking objects: 100% (10/10), done. Checking connectivity... done. user@host:~$
An ordinary OAuth request was spawned for authentication on https://github.com/login/oauth/authorize. The javascript executed in the browser seemed to interact with the gh tool through a local TCP connection on localhost:45454 which was the redirection target on authorisation (URL parameter: “redirect_uri=http://localhost:45454/callback”). The socket was rightfully not bound after the authentication had succeeded but this is definitely an attack vector, albeit hopefully only for locally running processes.
user@host:~$ cd coordinates/ user@host:~$:~/coordinates$ gh issue list Issues for mikini/coordinates There are no open issues miki@vcas-miki2:~/coordinates$ gh pr view no open pull requests found for branch "master" miki@vcas-miki2:~/coordinates$
miki@vcas-miki2:~/coordinates$ gh issue create Creating issue in mikini/coordinates ? Title Testing gh ? Body <Received> ? What's next? Preview in browser Opening github.com/mikini/coordinates/issues/new/ in your browser. miki@vcas-miki2:~/coordinates$ miki@vcas-miki2:~/coordinates$ gh issue create Creating issue in mikini/coordinates ? Title Testing gh tool ? Body <Received> ? What's next? [Use arrows to move, type to filter] > Preview in browser Submit Cancel https://github.com/mikini/coordinates/issues/1 miki@vcas-miki2:~/coordinates$
On the first issue creation interaction I selected “preview in browser” which opened a draft issue in the browser, and dumped me back into the shell on the command line. The second interaction actually resulted in #1.
The golang-backports PPA is maintained independently by Simon Eisenmann (credits: ~longsleep, @github, stdin.xyz) and carries packages up to:
There’s also an official PPA from the golang project (~gophers) which however only carries packages up to 1.11 for both.
user@host:~$ sudo add-apt-repository ppa:longsleep/golang-backports Golang 1.8, 1.9, 1.10, 1.11, 1.12, 1.13 and 1.14 PPA for Ubuntu More info: https://launchpad.net/~longsleep/+archive/ubuntu/golang-backports Press [ENTER] to continue or ctrl-c to cancel adding it gpg: keyring `/tmp/tmpvnuym97a/secring.gpg' created gpg: keyring `/tmp/tmpvnuym97a/pubring.gpg' created gpg: requesting key 56A3D45E from hkp server keyserver.ubuntu.com gpg: /tmp/tmpvnuym97a/trustdb.gpg: trustdb created gpg: key 56A3D45E: public key "Launchpad PPA for Simon Eisenmann" imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) OK user@host:~$ user@host:~$ sudo apt update Hit:1 http://dk.archive.ubuntu.com/ubuntu xenial InRelease Get:2 http://dk.archive.ubuntu.com/ubuntu xenial-updates InRelease [109 kB] ... ... Get:37 http://security.ubuntu.com/ubuntu xenial-security/universe DEP-11 64x64 Icons [194 kB] Get:38 http://security.ubuntu.com/ubuntu xenial-security/multiverse amd64 DEP-11 Metadata [2.468 B] Fetched 7.614 kB in 3s (2.346 kB/s) Reading package lists... Done Building dependency tree Reading state information... Done 419 packages can be upgraded. Run 'apt list --upgradable' to see them. user@host:~$ user@host:~$ apt list --upgradeable golang -a Listing... Done golang/xenial,xenial 2:1.13~1longsleep1+xenial all [upgradable from: 2:1.6-1ubuntu4] golang/xenial,xenial,now 2:1.6-1ubuntu4 all [installed,upgradable to: 2:1.13~1longsleep1+xenial] user@host:~$ user@host:~$ sudo apt install golang Reading package lists... Done Building dependency tree Reading state information... Done The following packages were automatically installed and are no longer required: golang-1.6 golang-1.6-doc golang-1.6-go golang-1.6-src Use 'sudo apt autoremove' to remove them. The following additional packages will be installed: golang-1.13 golang-1.13-doc golang-1.13-go golang-1.13-src golang-doc golang-go golang-src Recommended packages: golang-1.13-race-detector-runtime The following NEW packages will be installed golang-1.13 golang-1.13-doc golang-1.13-go golang-1.13-src The following packages will be upgraded: golang golang-doc golang-go golang-src 4 to upgrade, 4 to newly install, 0 to remove and 413 not to upgrade. Need to get 60,2 MB of archives. After this operation, 322 MB of additional disk space will be used. Do you want to continue? [Y/n] Get:1 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang-1.13-src amd64 1.13.4-1longsleep1+xenial [12,7 MB] Get:2 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang-1.13-go amd64 1.13.4-1longsleep1+xenial [44,9 MB] Get:3 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang-1.13-doc all 1.13.4-1longsleep1+xenial [2.542 kB] Get:4 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang-1.13 all 1.13.4-1longsleep1+xenial [25,2 kB] Get:5 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang-src amd64 2:1.13~1longsleep1+xenial [3.838 B] Get:6 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang-go amd64 2:1.13~1longsleep1+xenial [23,0 kB] Get:7 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang-doc all 2:1.13~1longsleep1+xenial [3.880 B] Get:8 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu xenial/main amd64 golang all 2:1.13~1longsleep1+xenial [3.826 B] Fetched 60,2 MB in 5s (10,8 MB/s) Selecting previously unselected package golang-1.13-src. (Reading database ... 460737 files and directories currently installed.) Preparing to unpack .../golang-1.13-src_1.13.4-1longsleep1+xenial_amd64.deb ... Unpacking golang-1.13-src (1.13.4-1longsleep1+xenial) ... Selecting previously unselected package golang-1.13-go. Preparing to unpack .../golang-1.13-go_1.13.4-1longsleep1+xenial_amd64.deb ... Unpacking golang-1.13-go (1.13.4-1longsleep1+xenial) ... Selecting previously unselected package golang-1.13-doc. Preparing to unpack .../golang-1.13-doc_1.13.4-1longsleep1+xenial_all.deb ... Unpacking golang-1.13-doc (1.13.4-1longsleep1+xenial) ... Selecting previously unselected package golang-1.13. Preparing to unpack .../golang-1.13_1.13.4-1longsleep1+xenial_all.deb ... Unpacking golang-1.13 (1.13.4-1longsleep1+xenial) ... Preparing to unpack .../golang-src_2%3a1.13~1longsleep1+xenial_amd64.deb ... Unpacking golang-src (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ... Preparing to unpack .../golang-go_2%3a1.13~1longsleep1+xenial_amd64.deb ... Unpacking golang-go (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ... Preparing to unpack .../golang-doc_2%3a1.13~1longsleep1+xenial_all.deb ... Unpacking golang-doc (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ... Preparing to unpack .../golang_2%3a1.13~1longsleep1+xenial_all.deb ... Unpacking golang (2:1.13~1longsleep1+xenial) over (2:1.6-1ubuntu4) ... Processing triggers for man-db (2.7.5-1) ... Setting up golang-1.13-src (1.13.4-1longsleep1+xenial) ... Setting up golang-1.13-go (1.13.4-1longsleep1+xenial) ... Setting up golang-1.13-doc (1.13.4-1longsleep1+xenial) ... Setting up golang-1.13 (1.13.4-1longsleep1+xenial) ... Setting up golang-src (2:1.13~1longsleep1+xenial) ... Setting up golang-go (2:1.13~1longsleep1+xenial) ... Setting up golang-doc (2:1.13~1longsleep1+xenial) ... Setting up golang (2:1.13~1longsleep1+xenial) ... user@host:~$ user@host:~$ go version go version go1.13.4 linux/amd64 user@host:~$
user@host:~$ git clone https://github.com/cli/cli .githubcli Cloning into '.githubcli'... remote: Enumerating objects: 168, done. remote: Counting objects: 100% (168/168), done. remote: Compressing objects: 100% (100/100), done. remote: Total 5577 (delta 93), reused 122 (delta 67), pack-reused 5409 Receiving objects: 100% (5577/5577), 7.53 MiB | 2.61 MiB/s, done. Resolving deltas: 100% (3269/3269), done. Checking connectivity... done. user@host:~$ user@host:~$ cd .githubcli user@host:~/.githubcli (master=)$ make go: downloading github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 go: downloading github.com/mitchellh/go-homedir v1.1.0 go: downloading github.com/mattn/go-colorable v0.1.6 go: downloading github.com/spf13/cobra v0.0.6 go: downloading gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 go: downloading github.com/mattn/go-isatty v0.0.12 go: downloading golang.org/x/text v0.3.2 go: extracting github.com/mitchellh/go-homedir v1.1.0 go: extracting github.com/mattn/go-colorable v0.1.6 go: extracting github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 go: extracting github.com/spf13/cobra v0.0.6 go: extracting github.com/mattn/go-isatty v0.0.12 go: downloading golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae go: downloading golang.org/x/crypto v0.0.0-20200219234226-1ad67e1f0ef4 go: downloading github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b go: downloading github.com/briandowns/spinner v1.9.0 go: extracting gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 go: downloading github.com/hashicorp/go-version v1.2.0 go: downloading github.com/spf13/pflag v1.0.5 go: downloading github.com/AlecAivazis/survey/v2 v2.0.7 go: downloading github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 go: downloading github.com/charmbracelet/glamour v0.1.1-0.20200304134224-7e5c90143acc go: extracting github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b go: extracting github.com/spf13/pflag v1.0.5 go: extracting github.com/hashicorp/go-version v1.2.0 go: downloading gopkg.in/yaml.v2 v2.2.8 go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.0 go: downloading github.com/henvic/httpretty v0.0.4 go: extracting github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 go: extracting github.com/briandowns/spinner v1.9.0 go: extracting github.com/AlecAivazis/survey/v2 v2.0.7 go: downloading github.com/fatih/color v1.7.0 go: extracting github.com/charmbracelet/glamour v0.1.1-0.20200304134224-7e5c90143acc go: downloading github.com/yuin/goldmark v1.1.24 go: downloading github.com/microcosm-cc/bluemonday v1.0.2 go: extracting gopkg.in/yaml.v2 v2.2.8 go: extracting github.com/henvic/httpretty v0.0.4 go: downloading github.com/olekukonko/tablewriter v0.0.4 go: downloading github.com/muesli/reflow v0.1.0 go: extracting github.com/fatih/color v1.7.0 go: extracting github.com/microcosm-cc/bluemonday v1.0.2 go: extracting github.com/cpuguy83/go-md2man/v2 v2.0.0 go: extracting golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae go: extracting github.com/muesli/reflow v0.1.0 go: extracting github.com/olekukonko/tablewriter v0.0.4 go: downloading golang.org/x/net v0.0.0-20200219183655-46282727080f go: extracting github.com/yuin/goldmark v1.1.24 go: downloading github.com/alecthomas/chroma v0.7.2-0.20200304075647-34d9c7143bf5 go: downloading github.com/mattn/go-runewidth v0.0.8 go: downloading github.com/muesli/termenv v0.4.0 go: downloading github.com/russross/blackfriday/v2 v2.0.1 go: extracting golang.org/x/crypto v0.0.0-20200219234226-1ad67e1f0ef4 go: extracting github.com/mattn/go-runewidth v0.0.8 go: extracting github.com/russross/blackfriday/v2 v2.0.1 go: downloading github.com/shurcooL/sanitized_anchor_name v1.0.0 go: extracting github.com/alecthomas/chroma v0.7.2-0.20200304075647-34d9c7143bf5 go: extracting github.com/shurcooL/sanitized_anchor_name v1.0.0 go: extracting github.com/muesli/termenv v0.4.0 go: downloading github.com/dlclark/regexp2 v1.2.0 go: downloading github.com/lucasb-eyer/go-colorful v1.0.3 go: downloading github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f go: downloading github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 go: extracting golang.org/x/text v0.3.2 go: extracting github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f go: extracting github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 go: extracting golang.org/x/net v0.0.0-20200219183655-46282727080f go: extracting github.com/lucasb-eyer/go-colorful v1.0.3 go: extracting github.com/dlclark/regexp2 v1.2.0 go: finding github.com/spf13/cobra v0.0.6 go: finding github.com/AlecAivazis/survey/v2 v2.0.7 go: finding github.com/henvic/httpretty v0.0.4 go: finding github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 go: finding github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b go: finding gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 go: finding github.com/spf13/pflag v1.0.5 go: finding github.com/hashicorp/go-version v1.2.0 go: finding github.com/mitchellh/go-homedir v1.1.0 go: finding github.com/briandowns/spinner v1.9.0 go: finding golang.org/x/text v0.3.2 go: finding github.com/cpuguy83/go-md2man/v2 v2.0.0 go: finding github.com/charmbracelet/glamour v0.1.1-0.20200304134224-7e5c90143acc go: finding github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 go: finding github.com/mattn/go-colorable v0.1.6 go: finding gopkg.in/yaml.v2 v2.2.8 go: finding github.com/russross/blackfriday/v2 v2.0.1 go: finding github.com/mattn/go-isatty v0.0.12 go: finding github.com/fatih/color v1.7.0 go: finding golang.org/x/crypto v0.0.0-20200219234226-1ad67e1f0ef4 go: finding github.com/muesli/termenv v0.4.0 go: finding golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae go: finding github.com/shurcooL/sanitized_anchor_name v1.0.0 go: finding github.com/yuin/goldmark v1.1.24 go: finding github.com/alecthomas/chroma v0.7.2-0.20200304075647-34d9c7143bf5 go: finding github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f go: finding github.com/dlclark/regexp2 v1.2.0 go: finding github.com/lucasb-eyer/go-colorful v1.0.3 go: finding github.com/muesli/reflow v0.1.0 go: finding github.com/microcosm-cc/bluemonday v1.0.2 go: finding github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 go: finding github.com/olekukonko/tablewriter v0.0.4 go: finding github.com/mattn/go-runewidth v0.0.8 go: finding golang.org/x/net v0.0.0-20200219183655-46282727080f user@host:~/.githubcli (master=)$
user@host:~/.githubcli (master=)$ ls -l bin/gh -rwxrwxr-x 1 user user 21097487 Mar 4 18:03 bin/gh user@host:~/.githubcli (master=)$ user@host:~/.githubcli (master=)$ file bin/gh bin/gh: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, not stripped user@host:~/.githubcli (master=)$ user@host:~/.githubcli (master=)$ ldd bin/gh linux-vdso.so.1 => (0x00007ffdc4329000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb1018c2000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb1014f8000) /lib64/ld-linux-x86-64.so.2 (0x00007fb101adf000) user@host:~/.githubcli (master=)$ user@host:~/.githubcli (master=)$ nm -D bin/gh U abort 00000000004fd140 T _cgo_panic 000000000045bf10 T _cgo_topofstack 00000000004fd190 T crosscall2 U __errno_location U __fprintf_chk U fputc U free U freeaddrinfo U fwrite U gai_strerror U getaddrinfo U getnameinfo U malloc U mmap U munmap U nanosleep U pthread_attr_destroy U pthread_attr_getstacksize U pthread_attr_init U pthread_cond_broadcast U pthread_cond_wait U pthread_create U pthread_detach U pthread_mutex_lock U pthread_mutex_unlock U pthread_sigmask U setenv U sigaction U sigaddset U sigemptyset U sigfillset U sigismember U __stack_chk_fail U stderr U strerror U unsetenv U __vfprintf_chk user@host:~/.githubcli (master=)$
user@host:~/.githubcli (master=)$ cd user@host:~$ echo 'export PATH="$HOME/.githubcli/bin:$PATH"' >> ~/.bash_profile user@host:~$ bash --login
user@host:~$ gh Work seamlessly with GitHub from the command line. GitHub CLI is in early stages of development, and we'd love to hear your feedback at <https://forms.gle/umxd3h31c7aMQFKG7> Usage: gh [command] Available Commands: help Help about any command issue Create and view issues pr Create, view, and checkout pull requests repo Create, clone, fork, and view repositories Flags: --help Show help for command -R, --repo OWNER/REPO Select another repository using the OWNER/REPO format --version Show gh version Use "gh [command] --help" for more information about a command. subcommand is required user@host:~$
Hit an odd browser behaviour today.
Trawling through some of those nice and dandy terms for a service (no I won’t tell) I followed a link and suddenly hit an “insecure connection” message from Firefox.
Examining the certificate using the usual “openssl s_client” and “openssl x509” tools surely enough revealed that the served certificate didn’t include the second-level but only on the third-level www sub-domain. Strangely enough I discovered that when entering the same URL directly into the address bar of Firefox the connection was somehow redirected to the www sub-domain and loaded fine without any complaints from Firefox.
Looking into what was happening on the wire using wget directed to not check the certificate (–no-check-certificate) and displaying server responses (–server-response/-S) revealed that the server behind the misconfigured certificate was aiming to issue a HTTP 301 redirect to the valid www sub-domain of the site (actual site replaced by foo.bar and localhost ip);
$ wget –server-response –no-check-certificate –output-document=/dev/null https://foo.bar –2018-11-15 18:59:14– https://foo.bar/ Resolving foo.bar (foo.bar)… 127.0.0.1 Connecting to foo.bar (foo.bar)|127.0.0.1|:443… connected. WARNING: no certificate subject alternative name matches requested host name ‘foo.bar’. HTTP request sent, awaiting response… HTTP/1.1 301 Moved Permanently Content-Type: text/html; charset=UTF-8 Location: https://www.foo.bar/ Date: Thu, 15 Nov 2018 17:59:13 GMT Content-Length: 152 Location: https://www.foo.bar/ [following] …
Apparently Firefox’s behaviour in this scenario differs depending on the method in which the user is supplying the URL, in some cases silently ignoring the TLS/SSL warning. A little more experimentation revealed that it was actually not the source of the URL, link followed versus one entered in address bar, that made any difference. Instead it is the presence of a trailing slash on the URL that triggers the silent suppression of the serious red flag that the second-level domain asked to be fetched is not present in the served certificate. I was fooled by the fact that when entering URLs in the address bar Firefox suggests ending the URL on a slash (‘/’) if it is not already present. Manually removing this when editing in the address bar also makes Firefox display the security warning. Alas, the link I originally followed was also missing the trailing slash and behaved as expected by throwing me into a security warning.
The whole “feature” of silently ignoring a security issue seemed very odd to me, but a bit of searching revealed that this was apparently championed by Google Chrome a couple of years ago. It is described in this servertastic post which also directs to a discussion on Twitter, with some key points replicated below, about its presence in Chrome and confirmation from a Chrome team member that the behaviour is intended.
Interesting. Chrome recognizes https ://onlineservices.nsdl.com has a cert valid only for www and redirects to https://www… @Scott_Helme pic.twitter.com/j9XdqiXqAI — Anand Bhat (@_anandbhat) October 26, 2016
Interesting. Chrome recognizes https ://onlineservices.nsdl.com has a cert valid only for www and redirects to https://www… @Scott_Helme pic.twitter.com/j9XdqiXqAI
— Anand Bhat (@_anandbhat) October 26, 2016
invalid cert for raw TLD but valid cert for www will trigger redirection down to www — Adrienne Porter Felt (@__apf__) October 26, 2016
invalid cert for raw TLD but valid cert for www will trigger redirection down to www
— Adrienne Porter Felt (@__apf__) October 26, 2016
The thread ends with a guy who had dug up the source code of the feature in Chromium (on which Chrome is based) known as “SSLCommonNameMismatchHandling” in file browser/ssl/common_name_mismatch_handler.cc (see all mentions across code base).
This has obviously also trickled down into Firefox, however, not much mention of that is to be found. Not even traces of it by some quick searches of the mozilla-central codebase. Some day I promise (really!) to dig through all source of Mozilla and hunt down the implementation, but for now I’ll revert to a bit of practical experimentation showing the behaviour in the different browsers and operating systems I happen to have access to at the moment;
So somewhere between 59.0.3 and 62.0.2 Firefox also implemented a policy of silently accepting invalid certificates when certain non-obvious criteria is met (is the redirect actually followed and certs checked, or is “www.” just prefixed?), but this happens only when the URL ends on a slash. Go figure…
Below you’ll find an illustrated guide for freeing the authentication mechanism used by the Google Authenticator app for Android or iPhone for use on your favorite device (anywhere an implementation is available). In fact the Authenticator is using a standards based 2FA (two factor authentication) scheme defined by OATH (Initiative for Open Authentication) and published in RFC6238 dubbed TOTP – Time-Based One-Time Password Algorithm (more Authenticator background and it’s basis HOTP).
This is a rather fine contraption but Google doesn’t advertise it very loudly being a standard instead locking the generated TOTP secret into a QR code that they will only imply are for use by their own Google Authenticator. That is not true as a host of alternative Android OTP apps are compatible and can read the QR codes as they are based upon the Authenticator’s legacy as an open source application which Google took private.
Login to your Google Account (maybe using the authenticator?) and go to Account -> Security -> Signin -> 2-step verification.
Locate the “Authenticator app” section and Click “CHANGE PHONE” (really “CHANGE TOTP SECRET”).
In my country’s locale, Danish, this is BTW mistranslated as “SKIFT TELEFONNUMMER” = change phone number);
You’ll now get a choice between either iPhone or Android, this will only affect the link to the app store shown on next screen which also contains the QR code, the one we are really after:
Right click the QR code image, select to save it and put it somewhere you can find it (~/Google_TOTP_QR.png might be sensible).
Install the QR-code decoder zbar for extracting the TOTP secet from the image and the OATH toolkit oathtool for generating future TOTP passwords using it. On Debian/Ubuntu this can be done by installing the packages zbar-tools and oathtool.
$ sudo apt install zbar-tools oathtool
Now extract the otpauth URI (seems to be a Google thing) by passing the image file to zbarimg;
$ zbarimg ~/Google_TOTP_QR.png QR-Code:otpauth://totp/Google%3Auser%40domain.com?secret=pca7uyfht7f6mfs7oiec4aeavxaevish&issuer=Google scanned 1 barcode symbols from 1 images in 0.02 seconds
The URI contains all parameters to input into the TOTP algorithm for generating a password usable for 2FA authentication, notably the secret key in base32 format. Defaults are not mentioned in the URI and are not necessary to specify explicitly for oathtool. So for the above URI specifying only a secret, a password can be generated as such;
$ oathtool --totp --base32 pca7uyfht7f6mfs7oiec4aeavxaevish 491293
“491293” being the password, having a default validity of 30 seconds (called step size because of the counter based nature of the HOTP behind it).
If your are interested in the defaults assumed by oathtool they can be viewed by supplying -v to it (not showing TOTP mode=SHA512, I later added this feature in my oath-toolkit fork, and opened a MR) ;
$ oathtool --totp --base32 pca7uyfht7f6mfs7oiec4aeavxaevish -v Hex secret: 7881fa60a79fcbe6165f72082e0080adc04aa247 Base32 secret: PCA7UYFHT7F6MFS7OIEC4AEAVXAEVISH Digits: 6 Window size: 0 Step size (seconds): 30 Start time: 1970-01-01 00:00:00 UTC (0) Current time: 2017-11-06 23:23:31 UTC (1510010611) Counter: 0x30007F7 (50333687) 133339
Enjoy having cut your reliance on the Google Autenticator, and opened up for your own choice of client:
Also see the dongleauth.info website for a list of other sites supporting TOTP and U2F.
Be sure to delete the QR code image when finished, and seek out a suitably secure place to store your TOTP secret. One solution could be using PGP encryption, maybe even through some clever management system such as pass.
Also educate yourself of the shortcomings of TOTP/HOTP and consider studying and using the FIDO U2F standard and related devices.