Skip to content

Instantly share code, notes, and snippets.

@brianredbeard
Last active March 8, 2024 00:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianredbeard/5437c72e7ee0246314e2ad40da4c8206 to your computer and use it in GitHub Desktop.
Save brianredbeard/5437c72e7ee0246314e2ad40da4c8206 to your computer and use it in GitHub Desktop.
NOOOOOOO disassemble

Quick Walkthrough

Option 1: The easy lazy route:

Step 1: Discover secrets in code:

https://github.com/noobaa/noobaa-core/blob/42ded19919e2a23a3faec404ae96090a819bc845/gocode/src/noobaa-operator/deploy/noobaa-operator.yaml#L9:

kind: Secret
apiVersion: v1
metadata:
  name: noobaaimages.azurecr.io
  labels:
    app: noobaa
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: eyJhdXRocyI6eyJub29iYWFpbWFnZXMuYXp1cmVjci5pbyI6eyJ1c2VybmFtZSI6ImJkOTFiYjVjLTE4MTUtNGE4OC1iOWY3LTk1NWY1MWI1YTE0MyIsInBhc3N3b3JkIjoiMDhlOTJkZTAtZTk3YS00NjE4LWE1NTgtNDQ4YzA0MzlkMjk4IiwiZW1haWwiOiJlcmFuLnRhbWlyQG5vb2JhYS5jb20iLCJhdXRoIjoiWW1RNU1XSmlOV010TVRneE5TMDBZVGc0TFdJNVpqY3RPVFUxWmpVeFlqVmhNVFF6T2pBNFpUa3laR1V3TFdVNU4yRXRORFl4T0MxaE5UVTRMVFEwT0dNd05ETTVaREk1T0E9PSJ9fX0=

Step 2: Unpack secrets

Next, since it's trivial to unpack that:

$ echo -n "eyJhdXRocyI6eyJub29iYWFpbWFnZXMuYXp1cmVjci5pbyI6eyJ1c2VybmFtZSI6ImJkOTFiYjVjLTE4MTUtNGE4OC1iOWY3LTk1NWY1MWI1YTE0MyIsInBhc3N3b3JkIjoiMDhlOTJkZTAtZTk3YS00NjE4LWE1NTgtNDQ4YzA0MzlkMjk4IiwiZW1haWwiOiJlcmFuLnRhbWlyQG5vb2JhYS5jb20iLCJhdXRoIjoiWW1RNU1XSmlOV010TVRneE5TMDBZVGc0TFdJNVpqY3RPVFUxWmpVeFlqVmhNVFF6T2pBNFpUa3laR1V3TFdVNU4yRXRORFl4T0MxaE5UVTRMVFEwT0dNd05ETTVaREk1T0E9PSJ9fX0=" | base64 -d | jq . 
{
  "auths": {
    "noobaaimages.azurecr.io": {
      "username": "bd91bb5c-1815-4a88-b9f7-955f51b5a143",
      "password": "08e92de0-e97a-4618-a558-448c0439d298",
      "email": "eran.tamir@noobaa.com",
      "auth": "YmQ5MWJiNWMtMTgxNS00YTg4LWI5ZjctOTU1ZjUxYjVhMTQzOjA4ZTkyZGUwLWU5N2EtNDYxOC1hNTU4LTQ0OGMwNDM5ZDI5OA=="
    }
  }
}

Step 3:

From there:

$ docker login noobaaimages.azurecr.io
Username: bd91bb5c-1815-4a88-b9f7-955f51b5a143
Password: 
WARNING! Your password will be stored unencrypted in /home/bharrington/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Now... this is ultimately assuming we had the source code. That being said, it din't really matter in the end.

Option 2: The "hard" way

Step 1: Binary analysis

When it comes to binary analysis, we need to keep in mind our standard toolset(s):

  • file
  • strings
  • gdb
  • binwalk
  • floss

We use each of these for it's own purpose. file and strings are mechanisms for quickly identifying what a file is and seeing what goodies it might contain. If it's a binary (and since I'm on a Linux machine i'll say "screw it" and limit this to ELF binaries and not PE, aka Windows) we can use gdb (aka the Gnu Debugger) to run the program and get some more info. On the other hand, if it happens to be some other type of file (firmware for example) we can use binwalk to dig through it.

When using file and strings this should ideally be done in a container. There have been documented vulnerabilities in the Linux binutils package in the past, so just play it safe.

To start:

$ file noobaa-operator 
noobaa-operator: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=3gULsYdEFl2hnQtEo0Zf/MMCpf2QhFXu_o4EQxF4z/xIHYZB0Sp6B-9PXNIPx7/wfhEYSyXZ7Gj7X4BDbn-, not stripped

So what do we know? It's an ELF binary, compiled for a 64-Bit Linux standard build system. It's statically linked, written in Go, and none of the debugging symbols have been stripped. Woohoo! this just got easier (and harder, but that's just because Go debugging is different from vanilla C).

So now we know that when we run strings on that binary we will get a bunch of info out of the symbol table, too.

$ strings noobaa-operator

For what it's worth, I'm not dumping that output in here because even just using grep to narrow that down to lines containing noobaa-operator there is over 50k lines.

But.... we know know that there is the potential for even more juicy tidbits... So let's dig further.

Step 2: Deep string analysis

Floss is a tool for extracting obfuscated strings from binaries. It's useful for digging out the endpoints malware is attempting to talk to, etc.

Personally, I like searching inside of Go binaries intended to talk to Kubernetes to hunt for secrets. So let's zoom out for a second and ask some questions:

  1. What format are Kubernetes Secrets stored in?

base64

  1. What character do many base64 strings end in?

=

Why do they end in that? Because of padding. Fortunately for us, this provides a "crib".

  1. What character set do we need to hunt for base64 strings?

A-Z a-z 0-9 + /

Note: As we mentioned.... the = is used for padding

Let's glue floss with a good tool for hunting for strings, grep:

$ floss noobaa-operator  | grep -E '[[:alnum:]/+]{80,}='
apisaposappsargsasn1aumlavx2basebetabindbitsbmi1bmi2bodyboolbullbytecallcap
cas1cas2cas3cas4cas5cas6casecentchancidrcirccodecommcongcopydArrdarrdatadatedeaddef=denydialdropelseemspenspenumermsetageumleuroexecfailfileflagflowfnoffromftpsfuncgotogziphArrhardharrheadhosthourhtmlhttpicmpidleigmpimaginfoint8intsiotaisiniumljobsjsonkey:kindlArrlanglarrleftlinkmacrmakemap[md5
a: %vacircacuteaeligaliasallOfallowalphaamd64argp=aringarrayasympb: %vbad
nbasicbatchbdquoblockboolsbreakburstbytescasp1casp2casp3cdatacedilcellschdirchmodchowncloseclubsconstcountcrarrdebugdeferdeltadepthdiamsecircemailemptyenum=equiverroreventexactexistextrafalsefatalfaultfcntlfieldfilesfloatforcefoundfraslfunc(gammagcinggetwdgob:
groupgzip;hostshttpsicirciexclimageimap2imap3imapsindexinfinint16int32int64ipNetiscsiitemsjson=kappakindslabellaquolceilldquolevellimitline
linuxlocallsquolstatmatchmdashmicrominusmkdirmonthmultinablaname=namesndashnodesnotinocircoeligolineomegaopen
oplusopts:panicparsepatchpathsphasepipe2pipespodIPpop3sportspoundprimeprintproc2protoproxyqueryradicrangeraquorceilrdquoreadyrightrolesroutersquorulesrune
sbquoscalescopesetupsigmasleepslicesocksspec:sse41sse42ssse3statestdinsvqxXszligtest.text/thetathorntildetimestitletls:
tokentradetransucircuint8uintsunionupsihutf-8valueverbswatchwritewwids (MB)
DEPRECATED: GitRepo is deprecated. To provision a container with a git repo,
mount an EmptyDir into an InitContainer that clones the repo using git, then
mount the EmptyDir into the Pod's
container.eyJhdXRocyI6eyJub29iYWFpbWFnZXMuYXp1cmVjci5pbyI6eyJ1c2VybmFtZSI6ImJkOTFiYjVjLTE4MTUtNGE4OC1iOWY3LTk1NWY1MWI1YTE0MyIsInBhc3N3b3JkIjoiMDhlOTJkZTAtZTk3YS00NjE4LWE1NTgtNDQ4YzA0MzlkMjk4IiwiZW1haWwiOiJlcmFuLnRhbWlyQG5vb2JhYS5jb20iLCJhdXRoIjoiWW1RNU1XSmlOV010TVRneE5TMDBZVGc0TFdJNVpqY3RPVFUxWmpVeFlqVmhNVFF6T2pBNFpUa3laR1V3TFdVNU4yRXRORFl4T0MxaE5UVTRMVFEwT0dNd05ETTVaREk1T0E9PSJ9fX0=List
of ports which should be made accessible on the pods selected for this rule.
Each item in this list is combined using a logical OR. If this field is empty or
missing, this rule matches all ports (traffic not restricted by port). If this
field is present and contains at least one item, then this rule allows traffic
only if the traffic matches at least one port in the list.Endpoints is a
collection of endpoints that implement the actual service. Example:

If markdown didn't hate my freedom, I could assure you that each of the 4 things which matched that regex (strings containing the base64 character set of at least 80 lines) pop back in bright red. A very gratifying color.

Let's check them out one by one:

String 1:

cas1cas2cas3cas4cas5cas6casecentchancidrcirccodecommcongcopydArrdarrdatadatedeaddef=

Immediately i'm pretty certain this is a red herring. Repeating strings and the words "code", "comm", "copy", etc make me dubious, still when we decode it:

q�5q�6q�7q�8q�9q�:q�q��r�r'kr*�r�^r��r��r�rt
�u��u�Zu�^u�u�

Yup. Junk.

String 2:

nbasicbatchbdquoblockboolsbreakburstbytescasp1casp2casp3cdatacedilcellschdirchmodchowncloseclubsconstcountcrarrdebugdeferdeltadepthdiamsecircemailemptyenum=

Also not expecting much on this one. "basic", "break", "burst", "bytes", et al. It's probably just coincidence that it ended with an =. Decode it to get:

�����ڵ�[v��nZ��(���y��-o+^�Ƭ�W����j�wq֭iǝ�W�[�ثr�u�h�w%�ǜ���r���.��+j��y��u�ޭץ��^��]���yȫq隊W��ܞ��

Affirmed. Maybe they're embedding some binary key material... unlikely though with all of those english words.

String 3:

ostshttpsicirciexclimageimap2imap3imapsindexinfinint16int32int64ipNetiscsiitemsjson=

Yawn. image, imap, index, int16, items, json... Likely these are defining functions. This is a statically compiled binary so that kindof stuff is going to happen somewhere... Decode it and we get:

��l��i�'"�Ȟ��b���f��)��x�j�"�ױ�w�)�ר��}��޸��^�+�(�zk#��

String 4:

eyJhdXRocyI6eyJub29iYWFpbWFnZXMuYXp1cmVjci5pbyI6eyJ1c2VybmFtZSI6ImJkOTFiYjVjLTE4MTUtNGE4OC1iOWY3LTk1NWY1MWI1YTE0MyIsInBhc3N3b3JkIjoiMDhlOTJkZTAtZTk3YS00NjE4LWE1NTgtNDQ4YzA0MzlkMjk4IiwiZW1haWwiOiJlcmFuLnRhbWlyQG5vb2JhYS5jb20iLCJhdXRoIjoiWW1RNU1XSmlOV010TVRneE5TMDBZVGc0TFdJNVpqY3RPVFUxWmpVeFlqVmhNVFF6T2pBNFpUa3laR1V3TFdVNU4yRXRORFl4T0MxaE5UVTRMVFEwT0dNd05ETTVaREk1T0E9PSJ9fX0=

Wink wink. Nudge Nudge. Look familiar? And the survey says:

{"auths":{"noobaaimages.azurecr.io":{"username":"bd91bb5c-1815-4a88-b9f7-955f51b5a143","password":"08e92de0-e97a-4618-a558-448c0439d298","email":"eran.tamir@noobaa.com","auth":"YmQ5MWJiNWMtMTgxNS00YTg4LWI5ZjctOTU1ZjUxYjVhMTQzOjA4ZTkyZGUwLWU5N2EtNDYxOC1hNTU4LTQ0OGMwNDM5ZDI5OA=="}}}

Tada.

Option 3: The l33t way

The secrets were also compiled into the binaries in a few locations. The best way to dig secrets out of a binary is, of course, a dissassembler and a little knowledge of Intel x86 assembly.

I'm not going to dig into this one. My former tool of choice "back in the day" was ollydbg. Then, when I became a FL/OSS (free, libre, open source software) user I was shit out of luck. This meant running it on a VM.

Later, circa 2009, a rad hex editor underwent a transformation into free mashup between ollydbg and Ida Pro, called Radare2. Now, despite the irony behind it the gold standard (in my opinion) of disassemblers is Ghidra... written by the United States National Security Agency.

I'll summarize what Ghidra can do with a screenshot:

ghidra screenshot

Basically, I loaded the binary and started searching for "secret". Pretty quickly the string "ImagePullSecret" came back. From there I went to the function definition, poked around and then found a spot where it was called and loaded into memory (the LEA assembly call to "load effective address" from the 64 bit register RAX).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment