gotchu 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gotchu-0.1.0/LICENSE +202 -0
- gotchu-0.1.0/PKG-INFO +99 -0
- gotchu-0.1.0/README.md +81 -0
- gotchu-0.1.0/gotchu/__init__.py +3 -0
- gotchu-0.1.0/gotchu/__main__.py +219 -0
- gotchu-0.1.0/gotchu/admin.py +156 -0
- gotchu-0.1.0/gotchu/browse.ps1 +15 -0
- gotchu-0.1.0/gotchu/check.py +307 -0
- gotchu-0.1.0/gotchu/collect.ps1 +69 -0
- gotchu-0.1.0/gotchu/exposure.py +200 -0
- gotchu-0.1.0/gotchu/harden.ps1 +28 -0
- gotchu-0.1.0/gotchu/harden.py +162 -0
- gotchu-0.1.0/gotchu/harden_apply.ps1 +80 -0
- gotchu-0.1.0/gotchu/pe.py +79 -0
- gotchu-0.1.0/gotchu/report.py +47 -0
- gotchu-0.1.0/gotchu/respond.py +118 -0
- gotchu-0.1.0/gotchu/scan.py +220 -0
- gotchu-0.1.0/gotchu/secrets_map.json +49 -0
- gotchu-0.1.0/gotchu/tripwire.py +364 -0
- gotchu-0.1.0/gotchu/tripwire_apply.ps1 +119 -0
- gotchu-0.1.0/gotchu/tripwire_watch.ps1 +169 -0
- gotchu-0.1.0/gotchu/ui.html +379 -0
- gotchu-0.1.0/gotchu/ui.py +124 -0
- gotchu-0.1.0/gotchu/vault.py +279 -0
- gotchu-0.1.0/gotchu.egg-info/PKG-INFO +99 -0
- gotchu-0.1.0/gotchu.egg-info/SOURCES.txt +38 -0
- gotchu-0.1.0/gotchu.egg-info/dependency_links.txt +1 -0
- gotchu-0.1.0/gotchu.egg-info/entry_points.txt +2 -0
- gotchu-0.1.0/gotchu.egg-info/top_level.txt +1 -0
- gotchu-0.1.0/pyproject.toml +52 -0
- gotchu-0.1.0/setup.cfg +4 -0
- gotchu-0.1.0/tests/test_admin.py +131 -0
- gotchu-0.1.0/tests/test_check.py +114 -0
- gotchu-0.1.0/tests/test_cli.py +54 -0
- gotchu-0.1.0/tests/test_exposure.py +64 -0
- gotchu-0.1.0/tests/test_harden.py +27 -0
- gotchu-0.1.0/tests/test_respond.py +45 -0
- gotchu-0.1.0/tests/test_scan.py +94 -0
- gotchu-0.1.0/tests/test_tripwire.py +129 -0
- gotchu-0.1.0/tests/test_vault.py +99 -0
gotchu-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
gotchu-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gotchu
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Free, local protection for Windows against password-stealing malware: it guards the safe, not just the door.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Project-URL: Repository, https://github.com/AnshMittal08/GotchU
|
|
7
|
+
Project-URL: Roadmap, https://github.com/AnshMittal08/GotchU/blob/main/ROADMAP.md
|
|
8
|
+
Keywords: security,windows,infostealer,malware,hardening
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Security
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# GotchU
|
|
20
|
+
|
|
21
|
+
[](https://github.com/AnshMittal08/GotchU/actions/workflows/ci.yml)
|
|
22
|
+
|
|
23
|
+
Antivirus guards the door. GotchU guards the safe.
|
|
24
|
+
|
|
25
|
+
Password-stealing malware does not need to break Windows. It runs once, copies your saved passwords,
|
|
26
|
+
signed-in sessions, chat logins, keys and wallets, and leaves. Antivirus often misses it, and removing
|
|
27
|
+
it afterwards does not un-steal anything.
|
|
28
|
+
|
|
29
|
+
GotchU is a free, local tool for Windows that works on that problem from both sides: it has your back,
|
|
30
|
+
and it catches the thief.
|
|
31
|
+
|
|
32
|
+
Status: early. It works on the author's Windows 11 Home PC; it has not been tested widely.
|
|
33
|
+
|
|
34
|
+
## What it does today
|
|
35
|
+
|
|
36
|
+
| Command | Question it answers |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `gotchu check <file>` | Is this download safe to open? Reads it without running it and looks for the packaging tricks malware uses, including password-protected archives and disk images. It opens zip files and folders; a 7z, RAR or other archive is reported as not looked inside, never as clean. |
|
|
39
|
+
| `gotchu scan` | Am I infected right now? Looks at running programs and what starts with Windows (tasks, services, the Start-up folder), the hosts file, and browser extensions loaded from a folder instead of the store. |
|
|
40
|
+
| `gotchu exposure` | What could a thief take from this PC today? Counts saved passwords, sessions, keys and wallets. Never shows or copies one. |
|
|
41
|
+
| `gotchu harden` | Which Windows protections are off? Turns four of them on, saving the old setting so `--undo` is exact. |
|
|
42
|
+
| `gotchu respond` | I ran something bad. What do I do? A checklist built from what is on this PC, in the order to do it. `--sites` adds the websites that have a password saved here (names only). |
|
|
43
|
+
| `gotchu tripwire` | Plants decoy files (fake wallets and fake browser logins) no honest program opens. When one is read you get an alarm, and with `--cut` that program loses its internet. It also lists any program, other than the owner, that reads your browser, Telegram or Discord logins. Signed programs installed in Program Files, such as antivirus and backup tools, are listed rather than alarmed; an unsigned program reading your logins is put at the top of the report. It also tells you if its watcher has stopped. |
|
|
44
|
+
| `gotchu vault` | Keeps key files encrypted with a passphrase, so a stolen copy is useless. `vault use` hands a key to one command and removes it afterwards. `vault passphrase` and `vault recovery` replace a forgotten passphrase or a lost recovery key. `vault backup` copies the vault, still encrypted, to another drive; `vault restore` brings it back. |
|
|
45
|
+
| `gotchu setup` | Installs or updates the small scripts that run with administrator rights, in `C:\Program Files\gotchu`. Done for you the first time harden or the tripwire needs them; run it yourself after updating GotchU. `--remove` takes them away again. |
|
|
46
|
+
| `gotchu ui` | A local window for check, scan, exposure and harden, and the tripwire's alarms and programs to review. |
|
|
47
|
+
|
|
48
|
+
## Run it
|
|
49
|
+
|
|
50
|
+
Needs Windows 10 or 11 and Python 3.10 or newer. No other packages.
|
|
51
|
+
|
|
52
|
+
python -m gotchu ui
|
|
53
|
+
python -m gotchu exposure
|
|
54
|
+
python -m gotchu tripwire --on
|
|
55
|
+
python -m gotchu vault create
|
|
56
|
+
python -m gotchu vault add --move my-server-key.pem
|
|
57
|
+
python -m gotchu vault use my-server-key.pem -- ssh -i {} user@host
|
|
58
|
+
|
|
59
|
+
Or install it and use the short command:
|
|
60
|
+
|
|
61
|
+
python -m pip install .
|
|
62
|
+
gotchu ui
|
|
63
|
+
|
|
64
|
+
With Smart App Control on (the first lock `gotchu harden` suggests), Windows may block the `gotchu` command
|
|
65
|
+
that pip makes, saying "An Application Control policy has blocked this file": it is an unsigned program.
|
|
66
|
+
`python -m gotchu` keeps working, because it runs through Python itself, which is signed. The planned
|
|
67
|
+
signed installer removes the difference.
|
|
68
|
+
|
|
69
|
+
Tests: `python -m unittest`. Every push is also linted and tested on Python 3.10 to 3.13 by GitHub Actions.
|
|
70
|
+
|
|
71
|
+
To help, see [CONTRIBUTING.md](CONTRIBUTING.md). To report a weakness, see [SECURITY.md](SECURITY.md).
|
|
72
|
+
|
|
73
|
+
## Promises
|
|
74
|
+
|
|
75
|
+
- **Local.** Nothing leaves your PC. No account.
|
|
76
|
+
- **Read-only unless you say so.** A change needs your yes and a Windows permission prompt, and can be undone.
|
|
77
|
+
- **Plain language.** Every finding says what was seen, why it matters and what to do.
|
|
78
|
+
- **Honest limits.** No tool stops every attack. The tripwire raises its alarm for decoys only; reads of real
|
|
79
|
+
login stores are listed for review, not yet alarmed; a patient attacker with administrator rights can switch any tool off. The vault protects
|
|
80
|
+
files at rest: a file you have taken out is an ordinary file again, and if you lose both the passphrase
|
|
81
|
+
and the recovery key, the files are gone. If GotchU itself sits in a folder your account can change (a
|
|
82
|
+
cloned copy, or Python installed just for you), a program running as you could change GotchU too;
|
|
83
|
+
`gotchu setup` tells you when that is the case.
|
|
84
|
+
|
|
85
|
+
## How it works
|
|
86
|
+
|
|
87
|
+
- [site/index.html](site/index.html): the landing page. One file; open it in a browser. Scrolling plays a
|
|
88
|
+
theft twice in 3D, once unguarded and once with GotchU.
|
|
89
|
+
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): the parts, what runs with which rights, and how the tripwire,
|
|
90
|
+
locks and vault work, as diagrams.
|
|
91
|
+
- [docs/USER_FLOWS.md](docs/USER_FLOWS.md): who it is for and the journeys it is designed around.
|
|
92
|
+
|
|
93
|
+
## Where it is going
|
|
94
|
+
|
|
95
|
+
See [ROADMAP.md](ROADMAP.md) and [docs/PRODUCT_PLAN.md](docs/PRODUCT_PLAN.md): unlocking the vault with Windows Hello, an alarm for reads of real browser and chat stores, and an installer.
|
|
96
|
+
|
|
97
|
+
## Licence
|
|
98
|
+
|
|
99
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
gotchu-0.1.0/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# GotchU
|
|
2
|
+
|
|
3
|
+
[](https://github.com/AnshMittal08/GotchU/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
Antivirus guards the door. GotchU guards the safe.
|
|
6
|
+
|
|
7
|
+
Password-stealing malware does not need to break Windows. It runs once, copies your saved passwords,
|
|
8
|
+
signed-in sessions, chat logins, keys and wallets, and leaves. Antivirus often misses it, and removing
|
|
9
|
+
it afterwards does not un-steal anything.
|
|
10
|
+
|
|
11
|
+
GotchU is a free, local tool for Windows that works on that problem from both sides: it has your back,
|
|
12
|
+
and it catches the thief.
|
|
13
|
+
|
|
14
|
+
Status: early. It works on the author's Windows 11 Home PC; it has not been tested widely.
|
|
15
|
+
|
|
16
|
+
## What it does today
|
|
17
|
+
|
|
18
|
+
| Command | Question it answers |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `gotchu check <file>` | Is this download safe to open? Reads it without running it and looks for the packaging tricks malware uses, including password-protected archives and disk images. It opens zip files and folders; a 7z, RAR or other archive is reported as not looked inside, never as clean. |
|
|
21
|
+
| `gotchu scan` | Am I infected right now? Looks at running programs and what starts with Windows (tasks, services, the Start-up folder), the hosts file, and browser extensions loaded from a folder instead of the store. |
|
|
22
|
+
| `gotchu exposure` | What could a thief take from this PC today? Counts saved passwords, sessions, keys and wallets. Never shows or copies one. |
|
|
23
|
+
| `gotchu harden` | Which Windows protections are off? Turns four of them on, saving the old setting so `--undo` is exact. |
|
|
24
|
+
| `gotchu respond` | I ran something bad. What do I do? A checklist built from what is on this PC, in the order to do it. `--sites` adds the websites that have a password saved here (names only). |
|
|
25
|
+
| `gotchu tripwire` | Plants decoy files (fake wallets and fake browser logins) no honest program opens. When one is read you get an alarm, and with `--cut` that program loses its internet. It also lists any program, other than the owner, that reads your browser, Telegram or Discord logins. Signed programs installed in Program Files, such as antivirus and backup tools, are listed rather than alarmed; an unsigned program reading your logins is put at the top of the report. It also tells you if its watcher has stopped. |
|
|
26
|
+
| `gotchu vault` | Keeps key files encrypted with a passphrase, so a stolen copy is useless. `vault use` hands a key to one command and removes it afterwards. `vault passphrase` and `vault recovery` replace a forgotten passphrase or a lost recovery key. `vault backup` copies the vault, still encrypted, to another drive; `vault restore` brings it back. |
|
|
27
|
+
| `gotchu setup` | Installs or updates the small scripts that run with administrator rights, in `C:\Program Files\gotchu`. Done for you the first time harden or the tripwire needs them; run it yourself after updating GotchU. `--remove` takes them away again. |
|
|
28
|
+
| `gotchu ui` | A local window for check, scan, exposure and harden, and the tripwire's alarms and programs to review. |
|
|
29
|
+
|
|
30
|
+
## Run it
|
|
31
|
+
|
|
32
|
+
Needs Windows 10 or 11 and Python 3.10 or newer. No other packages.
|
|
33
|
+
|
|
34
|
+
python -m gotchu ui
|
|
35
|
+
python -m gotchu exposure
|
|
36
|
+
python -m gotchu tripwire --on
|
|
37
|
+
python -m gotchu vault create
|
|
38
|
+
python -m gotchu vault add --move my-server-key.pem
|
|
39
|
+
python -m gotchu vault use my-server-key.pem -- ssh -i {} user@host
|
|
40
|
+
|
|
41
|
+
Or install it and use the short command:
|
|
42
|
+
|
|
43
|
+
python -m pip install .
|
|
44
|
+
gotchu ui
|
|
45
|
+
|
|
46
|
+
With Smart App Control on (the first lock `gotchu harden` suggests), Windows may block the `gotchu` command
|
|
47
|
+
that pip makes, saying "An Application Control policy has blocked this file": it is an unsigned program.
|
|
48
|
+
`python -m gotchu` keeps working, because it runs through Python itself, which is signed. The planned
|
|
49
|
+
signed installer removes the difference.
|
|
50
|
+
|
|
51
|
+
Tests: `python -m unittest`. Every push is also linted and tested on Python 3.10 to 3.13 by GitHub Actions.
|
|
52
|
+
|
|
53
|
+
To help, see [CONTRIBUTING.md](CONTRIBUTING.md). To report a weakness, see [SECURITY.md](SECURITY.md).
|
|
54
|
+
|
|
55
|
+
## Promises
|
|
56
|
+
|
|
57
|
+
- **Local.** Nothing leaves your PC. No account.
|
|
58
|
+
- **Read-only unless you say so.** A change needs your yes and a Windows permission prompt, and can be undone.
|
|
59
|
+
- **Plain language.** Every finding says what was seen, why it matters and what to do.
|
|
60
|
+
- **Honest limits.** No tool stops every attack. The tripwire raises its alarm for decoys only; reads of real
|
|
61
|
+
login stores are listed for review, not yet alarmed; a patient attacker with administrator rights can switch any tool off. The vault protects
|
|
62
|
+
files at rest: a file you have taken out is an ordinary file again, and if you lose both the passphrase
|
|
63
|
+
and the recovery key, the files are gone. If GotchU itself sits in a folder your account can change (a
|
|
64
|
+
cloned copy, or Python installed just for you), a program running as you could change GotchU too;
|
|
65
|
+
`gotchu setup` tells you when that is the case.
|
|
66
|
+
|
|
67
|
+
## How it works
|
|
68
|
+
|
|
69
|
+
- [site/index.html](site/index.html): the landing page. One file; open it in a browser. Scrolling plays a
|
|
70
|
+
theft twice in 3D, once unguarded and once with GotchU.
|
|
71
|
+
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): the parts, what runs with which rights, and how the tripwire,
|
|
72
|
+
locks and vault work, as diagrams.
|
|
73
|
+
- [docs/USER_FLOWS.md](docs/USER_FLOWS.md): who it is for and the journeys it is designed around.
|
|
74
|
+
|
|
75
|
+
## Where it is going
|
|
76
|
+
|
|
77
|
+
See [ROADMAP.md](ROADMAP.md) and [docs/PRODUCT_PLAN.md](docs/PRODUCT_PLAN.md): unlocking the vault with Windows Hello, an alarm for reads of real browser and chat stores, and an installer.
|
|
78
|
+
|
|
79
|
+
## Licence
|
|
80
|
+
|
|
81
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from . import __version__, check, exposure, harden, report, respond, scan, tripwire
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _choose_passphrase(getpass, prompt, nothing):
|
|
10
|
+
"""Ask for a new passphrase twice. None (after saying why) if it is too short or the two differ."""
|
|
11
|
+
passphrase = getpass.getpass(f"{prompt} (at least 10 characters; a few random words work well): ")
|
|
12
|
+
if len(passphrase) < 10:
|
|
13
|
+
print(f"Too short. {nothing}")
|
|
14
|
+
return None
|
|
15
|
+
if passphrase != getpass.getpass("Type it again: "):
|
|
16
|
+
print(f"The two did not match. {nothing}")
|
|
17
|
+
return None
|
|
18
|
+
return passphrase
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
RECOVERY_NOTE = ("Write this on paper now and keep it away from this PC. It is shown only once.\n"
|
|
22
|
+
"If you forget the passphrase, this key is the only other way in. Lose both and the\n"
|
|
23
|
+
"files in the vault are gone for good.")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _vault(args):
|
|
27
|
+
import getpass
|
|
28
|
+
import os
|
|
29
|
+
|
|
30
|
+
from . import vault
|
|
31
|
+
try:
|
|
32
|
+
if args.action == "create":
|
|
33
|
+
if vault.exists():
|
|
34
|
+
print("There is already a vault on this PC.")
|
|
35
|
+
return 1
|
|
36
|
+
passphrase = _choose_passphrase(getpass, "Choose a passphrase", "Nothing was created.")
|
|
37
|
+
if passphrase is None:
|
|
38
|
+
return 1
|
|
39
|
+
recovery = vault.create(passphrase)
|
|
40
|
+
print(f"\nVault created in {vault.FOLDER}\n\nRECOVERY KEY: {recovery}\n\n{RECOVERY_NOTE}")
|
|
41
|
+
return 0
|
|
42
|
+
if args.action == "restore":
|
|
43
|
+
vault.restore(args.folder)
|
|
44
|
+
print(f"Vault restored from {args.folder}. It opens with the passphrase or recovery key it had when it was backed up.")
|
|
45
|
+
return 0
|
|
46
|
+
if not vault.exists():
|
|
47
|
+
print("There is no vault yet. Make one with: gotchu vault create")
|
|
48
|
+
return 1
|
|
49
|
+
if args.action == "backup":
|
|
50
|
+
count = vault.backup(args.folder)
|
|
51
|
+
print(f"Copied the vault ({count} files, still encrypted) to {args.folder}.\n"
|
|
52
|
+
"The copy is useless without your passphrase or recovery key, so it is safe on a USB stick or in cloud storage.")
|
|
53
|
+
return 0
|
|
54
|
+
key = vault.unlock(getpass.getpass("Vault passphrase (or recovery key): "))
|
|
55
|
+
if args.action == "list":
|
|
56
|
+
print("\n".join(sorted(vault.names(key))) or "The vault is empty.")
|
|
57
|
+
elif args.action == "add":
|
|
58
|
+
for path in args.paths:
|
|
59
|
+
name = vault.add(key, path, name=args.name if len(args.paths) == 1 else None, move=args.move)
|
|
60
|
+
print(f"{name}: in the vault" + (", original deleted." if args.move else
|
|
61
|
+
f". The original is still at {path} - delete it, or add with --move."))
|
|
62
|
+
if args.move:
|
|
63
|
+
print("A deleted file can sometimes be recovered from the disk. If a key was ever exposed, replace it.")
|
|
64
|
+
elif args.action == "get":
|
|
65
|
+
target = args.to or args.name
|
|
66
|
+
if os.path.exists(target):
|
|
67
|
+
print(f"{target} already exists. Nothing was written.")
|
|
68
|
+
return 1
|
|
69
|
+
with open(target, "wb") as f:
|
|
70
|
+
f.write(vault.get(key, args.name))
|
|
71
|
+
print(f"Written to {target}. It is an ordinary file again - delete it when you are done.")
|
|
72
|
+
elif args.action == "use":
|
|
73
|
+
command = [part for part in args.run if part != "--"]
|
|
74
|
+
if not command:
|
|
75
|
+
print("Give the command to run, for example: gotchu vault use server.pem -- ssh -i {} user@host")
|
|
76
|
+
return 1
|
|
77
|
+
return vault.use(key, args.name, command)
|
|
78
|
+
elif args.action == "passphrase":
|
|
79
|
+
passphrase = _choose_passphrase(getpass, "Choose a new passphrase", "Nothing was changed.")
|
|
80
|
+
if passphrase is None:
|
|
81
|
+
return 1
|
|
82
|
+
vault.change_passphrase(key, passphrase)
|
|
83
|
+
print("Passphrase changed. The old one no longer opens the vault; your recovery key still does.")
|
|
84
|
+
elif args.action == "recovery":
|
|
85
|
+
recovery = vault.replace_recovery(key)
|
|
86
|
+
print(f"\nNEW RECOVERY KEY: {recovery}\n\nThe old recovery key no longer opens the vault.\n{RECOVERY_NOTE}")
|
|
87
|
+
else:
|
|
88
|
+
vault.remove(key, args.name)
|
|
89
|
+
print(f"{args.name} removed from the vault.")
|
|
90
|
+
return 0
|
|
91
|
+
except vault.WrongSecret:
|
|
92
|
+
print("That did not open the vault. Nothing was changed.")
|
|
93
|
+
except KeyError as e:
|
|
94
|
+
print(e.args[0])
|
|
95
|
+
except (OSError, ValueError) as e:
|
|
96
|
+
print(e)
|
|
97
|
+
return 1
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _setup(args):
|
|
101
|
+
from . import admin
|
|
102
|
+
ok, message = admin.remove() if args.remove else admin.install()
|
|
103
|
+
print(message)
|
|
104
|
+
if ok and not args.remove:
|
|
105
|
+
if admin.own_folder_writable():
|
|
106
|
+
print(f"\nNote: gotchu itself is in a folder your account can change ({admin.HERE}). A program running as\n"
|
|
107
|
+
"you could change it, including what it asks Windows to run as administrator. For the strongest\n"
|
|
108
|
+
"setup, install gotchu with a Python that is installed for all users, in Program Files.")
|
|
109
|
+
if tripwire.status()["on"]:
|
|
110
|
+
print("\nThe tripwire is on: run gotchu tripwire --on once more so its watcher uses the new version.")
|
|
111
|
+
return 0 if ok else 1
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def main(argv=None):
|
|
115
|
+
parser = argparse.ArgumentParser(prog="gotchu", description="Free, local, read-only PC safety checks.")
|
|
116
|
+
parser.add_argument("--version", action="version", version=__version__)
|
|
117
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
118
|
+
p = sub.add_parser("check", help="inspect a download (zip, folder or file) without running it")
|
|
119
|
+
p.add_argument("path")
|
|
120
|
+
p.add_argument("--json", action="store_true", help="print the result as JSON")
|
|
121
|
+
p = sub.add_parser("scan", help="look for signs that this PC is infected right now")
|
|
122
|
+
p.add_argument("--json", action="store_true", help="print the result as JSON")
|
|
123
|
+
p = sub.add_parser("exposure", help="show what a thief could take from this PC right now (counts only)")
|
|
124
|
+
p.add_argument("--json", action="store_true", help="print the result as JSON")
|
|
125
|
+
p = sub.add_parser("harden", help="show which Windows protections are on; turn one on or put it back")
|
|
126
|
+
p.add_argument("--json", action="store_true", help="print the result as JSON")
|
|
127
|
+
changeable = [k["key"] for k in harden.LOCKS if k["can_apply"]]
|
|
128
|
+
p.add_argument("--on", choices=changeable, metavar="LOCK", help="turn on: " + ", ".join(changeable))
|
|
129
|
+
p.add_argument("--undo", choices=changeable, metavar="LOCK", help="put a lock back the way it was")
|
|
130
|
+
p = sub.add_parser("tripwire", help="decoy files that raise an alarm when a thief reads them")
|
|
131
|
+
p.add_argument("--json", action="store_true", help="print the result as JSON")
|
|
132
|
+
p.add_argument("--on", action="store_true", help="plant the decoys and start watching (alert only)")
|
|
133
|
+
p.add_argument("--cut", action="store_true", help="with --on: also block the reading program from the internet")
|
|
134
|
+
p.add_argument("--off", action="store_true", help="remove the decoys and put Windows back as it was")
|
|
135
|
+
p.add_argument("--restore", action="store_true", help="after an alarm: lift the internet blocks and clear the alarm")
|
|
136
|
+
p = sub.add_parser("vault", help="keep key files encrypted so a stolen copy is useless")
|
|
137
|
+
act = p.add_subparsers(dest="action", required=True)
|
|
138
|
+
act.add_parser("create", help="make the vault and choose its passphrase")
|
|
139
|
+
a = act.add_parser("add", help="encrypt files into the vault")
|
|
140
|
+
a.add_argument("paths", nargs="+")
|
|
141
|
+
a.add_argument("--move", action="store_true", help="delete the original once the vault copy is verified")
|
|
142
|
+
a.add_argument("--name", help="store a single file under another name")
|
|
143
|
+
act.add_parser("list", help="show what is in the vault")
|
|
144
|
+
a = act.add_parser("get", help="take a file out as an ordinary file")
|
|
145
|
+
a.add_argument("name")
|
|
146
|
+
a.add_argument("--to", help="where to write it (default: this folder)")
|
|
147
|
+
a = act.add_parser("use", help="run a command with the file present only while it runs")
|
|
148
|
+
a.add_argument("name")
|
|
149
|
+
a.add_argument("run", nargs=argparse.REMAINDER, help="the command; {} is replaced by the file's path")
|
|
150
|
+
a = act.add_parser("remove", help="delete a file from the vault")
|
|
151
|
+
a.add_argument("name")
|
|
152
|
+
act.add_parser("passphrase", help="choose a new passphrase (opens with the old one or the recovery key)")
|
|
153
|
+
act.add_parser("recovery", help="make a new recovery key; the old one stops working")
|
|
154
|
+
a = act.add_parser("backup", help="copy the vault, still encrypted, to another folder or drive")
|
|
155
|
+
a.add_argument("folder", help="a new or empty folder")
|
|
156
|
+
a = act.add_parser("restore", help="bring a backed-up vault back onto a PC that has none")
|
|
157
|
+
a.add_argument("folder", help="the folder a backup was copied to")
|
|
158
|
+
p = sub.add_parser("respond", help="after running something bad: what to do, in what order")
|
|
159
|
+
p.add_argument("--json", action="store_true", help="print the result as JSON")
|
|
160
|
+
p.add_argument("--sites", action="store_true", help="also list the websites with a password saved on this PC (names only)")
|
|
161
|
+
p = sub.add_parser("setup", help="install or update gotchu's administrator helpers in Program Files")
|
|
162
|
+
p.add_argument("--remove", action="store_true", help="remove them, once nothing gotchu turned on still needs them")
|
|
163
|
+
p = sub.add_parser("ui", help="open the gotchu window in your browser")
|
|
164
|
+
p.add_argument("path", nargs="?", help="a download to check as soon as the window opens")
|
|
165
|
+
p.add_argument("--no-browser", action="store_true", help="start without opening a browser")
|
|
166
|
+
args = parser.parse_args(argv)
|
|
167
|
+
|
|
168
|
+
if args.command == "ui":
|
|
169
|
+
from . import ui
|
|
170
|
+
return ui.serve(open_browser=not args.no_browser, path=args.path)
|
|
171
|
+
|
|
172
|
+
if args.command == "vault":
|
|
173
|
+
return _vault(args)
|
|
174
|
+
|
|
175
|
+
if args.command == "setup":
|
|
176
|
+
return _setup(args)
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
return _run(args)
|
|
180
|
+
except report.CouldNotRun as e:
|
|
181
|
+
print(e)
|
|
182
|
+
return 3
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _run(args):
|
|
186
|
+
if args.command == "harden" and (args.on or args.undo):
|
|
187
|
+
ok, message = harden.change(args.on or args.undo, undo=bool(args.undo))
|
|
188
|
+
print(message)
|
|
189
|
+
return 0 if ok else 1
|
|
190
|
+
|
|
191
|
+
if args.command == "tripwire" and (args.on or args.off or args.restore):
|
|
192
|
+
ok, message = tripwire.change("on" if args.on else "off" if args.off else "restore", cut=args.cut)
|
|
193
|
+
print(message)
|
|
194
|
+
return 0 if ok else 1
|
|
195
|
+
|
|
196
|
+
if args.command == "check":
|
|
197
|
+
if not os.path.exists(args.path):
|
|
198
|
+
raise report.CouldNotRun(f"{args.path} does not exist. Check the path and try again.")
|
|
199
|
+
try:
|
|
200
|
+
result = check.result(args.path)
|
|
201
|
+
except OSError as e:
|
|
202
|
+
raise report.CouldNotRun(f"Windows would not let gotchu read {args.path} ({e.strerror or e}). "
|
|
203
|
+
"Try a copy in your Downloads folder.") from None
|
|
204
|
+
elif args.command == "tripwire":
|
|
205
|
+
result = tripwire.result()
|
|
206
|
+
elif args.command == "exposure":
|
|
207
|
+
result = exposure.result()
|
|
208
|
+
elif args.command == "respond":
|
|
209
|
+
result = respond.result(with_sites=args.sites)
|
|
210
|
+
else:
|
|
211
|
+
result = scan.result() if args.command == "scan" else harden.result()
|
|
212
|
+
print(json.dumps(result, indent=2) if args.json else report.render(result))
|
|
213
|
+
if args.command == "respond" and args.sites and not args.json:
|
|
214
|
+
print(f"\nWebsites with a password saved on this PC ({len(result['sites'])}):\n" + "\n".join(result["sites"]))
|
|
215
|
+
return {"danger": 2, "warn": 1}.get(result["level"], 0)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
if __name__ == "__main__":
|
|
219
|
+
sys.exit(main())
|