Hacker News new | ask | show | jobs
by jbverschoor 1330 days ago
What's the 'best' way to find out if there are binaries in which libssl is statically linked?
2 comments

If you're using distro packages, their own "packaging policy" should offer some level of assurance via policy about static linking (since as far as I know, all major distros dynamically link, to make this kind of bugfix easier).

If you're talking non distro packages (proprietary, or anything built manually from PPA or equivalent, or binaries dumped inside containers), this won't help.

Sure, but there might also be binaries outside the distro which link things statically, because makes distribution easier.

This is one of the "benefits" of go, where afaik many things are linked statically.

I'm currently playing around with grepping some function-names to find out if something uses libssl, and then check if ldd to see if libssl is loaded dynamically or not.

> Sure, but there might also be binaries outside the distro which link things statically, because makes distribution easier.

Then you'd use ldd to print the shared objects (shared libraries) required by each program or shared object: find … | xargs ldd.

> This is one of the "benefits" of go, where afaik many things are linked statically.

The static linking makes the situation worse: with dynamic link you update one package, and then restart any currently running processes. There are even helpful utilities to help you do the latter:

* https://packages.debian.org/search?keywords=needrestart

* https://packages.ubuntu.com/search?keywords=needrestart

Every single binary that is statically linked needs to be recompiled.

> Every single binary that is statically linked needs to be recompiled.

Exactly my point

Indeed - this is one of the positives of Go, as all the dependencies get linked statically, giving nice portable "single binary" solutions.

Grepping function names seems a reasonable approach, as long as you're not trying to detect something that is obfuscating its use of libssl (i.e. by mangling strings together).

It appears if you strip a binary, any definitive information about the libraries linked in statically is lost, beyond function names and argument combinations. I believe there are tools in IDA and similar, which can match functions based on their input argument types and name. That might help you match to a rough version of the upstream library, if parameters changed.

Unsure why people keep referring to static linking as a positive in this thread? Downstream consumers of statically-linked binaries have no practical way to scan their systems for known-vulnerable versions of libraries, that seems a profoundly negative consequence to me.
In Go you can use "go version -m my-go-binary" and get a list of dependencies and other build information. For example (may wrap a bit ugly on HN):

  [~]% go version -m =godoc
  /home/belta/bin/godoc: go1.18.3
          path    golang.org/x/tools/cmd/godoc
          mod     golang.org/x/tools      v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
          dep     github.com/yuin/goldmark        v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
          dep     golang.org/x/mod        v0.6.0-dev.0.20220419223038-86c51ed26bb4        h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
          dep     golang.org/x/net        v0.0.0-20220722155237-a158d28d115b      h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
          dep     golang.org/x/sys        v0.0.0-20220722155257-8c9f86f7a55f      h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
          build   -compiler=gc
          build   CGO_ENABLED=0
          build   GOARCH=amd64
          build   GOOS=linux
          build   GOAMD64=v1
So scanning your binaries, if you want, is fairly easy.

Other than that, this is the "Great Static vs. Dynamic Linking Debate", which has been done quite a few times. I have little desire to repeat it, but both approaches have their advantages and downsides, and with good tooling (like the above) I think many downsides of static linking can be managed quite well.

That's a great solution, actually. I'm not familiar with go, but I thought it compiled to native code and did not require a virtual machine at runtime. So is this metadata enforced/inserted by the compiler into the binary, or does it require specific build tooling that may or may not be available on end-user systems?
Unfortunately that shows the Go libraries involved, but not the C libraries those Go libraries depend on (right?). So that might tell me that a Go program includes 'crypto', but not whether or not that 'crypto' linked in OpenSSL 1.1.1 or OpenSSL 3.x.

So the static linking dependency analysis problem remains.

Indeed, there are certainly good reasons to statically link programs, but this type of security issue is the complete opposite, it's a known drawback that you may accept in exchange for the other benefits of static linking
Search the binaries for strings/messages that are unique to libssl. It's the only way (and it still doesn't give a conclusive answer) if the provenance of the binary is unknown.