winchecksec icon indicating copy to clipboard operation
winchecksec copied to clipboard

Pass a directory as an argument

Open duraki opened this issue 2 years ago • 12 comments

Hi! It would be nice if we could pass directory as an <file> / <dir> argument. A lot of times when we are looking for a potential target in exploitable binary, we look in all external PE inside the target installation and the dependencies.

Right now, we have to check each PE separately for our $TARGET (manually through cli or via bash script). A more natively supported way would be awesome, something like:

> C:\winchecksec.exe -d path/to/dir/*.dll    # does the sec check on all .dll
> C:\winchecksec.exe -d path/to/dir/*.exe    # does the sec check on all .exe

Searched the repo but couldn't find this option.

Hotfix for now:

$ for FILE in *; do ./winchecksec $FILE; done  # ugly, but it works

duraki avatar Mar 14 '22 11:03 duraki

I'm not sure I understand: does winchecksec *.{exe,dll} not work for you?

We check every file passed into us, so a normal glob should work just fine. Could you make sure that you're running the latest release (3.0.2)?

woodruffw avatar Mar 14 '22 14:03 woodruffw

Nop, that doesn't work.

$ winchecksec .{exe,dll}
Couldn't load file; corrupt or not a PE?
Syntax : /Users/hduraki/utils/winchecksec/winchecksec [--json] <file [file ...]>
Example: /Users/hduraki/utils/winchecksec/winchecksec --json doom2.exe
  -j/--json will output JSON to stdout

Actually tried it different ways in both MacOS/Windows/Linux but same results.

Edit: Yes I'm on latest release.

$ winchecksec -V
Winchecksec version 3.0.2

duraki avatar Mar 14 '22 15:03 duraki

Could you make sure you ran the right glob? It needs to be *.{exe,dll} not .{exe,dll} -- the latter expands to .exe .dll, which probably won't match any real files.

I'll test locally in a moment, but I just visually confirmed from the source code that we do indeed check every file passed to us:

    for (auto path = std::next(cmdl.begin()); path != cmdl.end(); ++path) {
        try {
            checksec::Checksec csec(*path);

            if (json) {
                results.push_back(csec);
            } else {
                std::cout << "Results for: " << *path << '\n';
                std::cout << csec << '\n';
            }
        } catch (checksec::ChecksecError& error) {
            std::cerr << error.what() << '\n';
            usage(argv);
            return 2;
        } catch (...) {
            std::cerr << "General error" << '\n';
            usage(argv);
            return 3;
        }
    }

woodruffw avatar Mar 14 '22 16:03 woodruffw

Sorry for that typo. Still the same tho.

$ winchecksec *.{exe,dll}
zsh: no matches found: *.exe

So I thought it must be zsh quirk? But then with sh:

/bin/sh
sh-3.2$ /Users/hduraki/utils/winchecksec/winchecksec *.{exe,dll}
Couldn't load file; corrupt or not a PE?
Syntax : /Users/hduraki/utils/winchecksec/winchecksec [--json] <file [file ...]>
Example: /Users/hduraki/utils/winchecksec/winchecksec --json doom2.exe
  -j/--json will output JSON to stdout

And bourne shell as well:

bash-3.2$ /Users/hduraki/utils/winchecksec/winchecksec *.{exe,dll}
Couldn't load file; corrupt or not a PE?
Syntax : /Users/hduraki/utils/winchecksec/winchecksec [--json] <file [file ...]>
Example: /Users/hduraki/utils/winchecksec/winchecksec --json doom2.exe
  -j/--json will output JSON to stdout

Tested on latest MacOS.

duraki avatar Mar 15 '22 08:03 duraki

@woodruffw could you replicate?

duraki avatar Apr 05 '22 09:04 duraki

Windows hotfix for now:

> for %i in (*.*) do winchecksec.exe %i

duraki avatar Apr 05 '22 10:04 duraki

Sorry, this fell of my radar completely. Trying now...

woodruffw avatar Apr 05 '22 13:04 woodruffw

I can't reproduce this locally:

$ ./winchecksec ../test/assets/32/*.exe

...audits all of the EXEs under that directory.

Example output:

Results for: ../test/assets/32/pegoat-authenticode.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "Present"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-ineffective-cfg-no-dynamicbase.exe
Dynamic Base    : "NotPresent"
ASLR            : "NotPresent"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-no-cetcompat.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-no-cfg.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-no-dynamicbase.exe
Dynamic Base    : "NotPresent"
ASLR            : "NotPresent"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-no-gs.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-no-integritycheck.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-no-nxcompat.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "NotPresent"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-no-safeseh.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat-yes-cfg.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "Present"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

Results for: ../test/assets/32/pegoat.exe
Dynamic Base    : "Present"
ASLR            : "Present"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation       : "Present"
NX              : "Present"
SEH             : "Present"
CFG             : "NotPresent"
RFG             : "NotPresent"
SafeSEH         : "NotPresent"
GS              : "Present"
Authenticode    : "NotPresent"
.NET            : "NotPresent"

woodruffw avatar Apr 05 '22 13:04 woodruffw

Looking at your globs: I'm not sure if you were running in a directory that had any executables or other auditable files in it.

The ZSH error is the one ZSH gives you when a glob expands to nothing; Bash and the standard sh both return the glob itself if nothing matches (which then naturally fails, since *.{exe,dll} isn't a file). So you should double check that your directory actually has the files you expect in it, and that they're visible to your shell (i.e., not hidden behind some weird permission or ACL).

woodruffw avatar Apr 05 '22 13:04 woodruffw

Ping: were you able to resolve this? I can confirm that globs work correctly for me locally, on all of Winchecksec's supported hosts.

woodruffw avatar Aug 10 '22 14:08 woodruffw

...except for Windows of course, since Windows doesn't have shell-native globbing.

Looks like I misread this a little: if you're still seeing the problem on Windows, it's because the Windows basic shell (cmd.exe) just doesn't support globbing. There isn't much we can do about that on Winchecksec's side.

woodruffw avatar Aug 10 '22 14:08 woodruffw

Yeah I meant for WinNT. I think the first post shows a viable option. Just scan for globs through the app interface and voila :)

duraki avatar Aug 11 '22 12:08 duraki