Difficulty
easyCategories
revDescription
Feel like you have been transported back in time by looking at this lovely .NET WinForms application.
Note: This challenge only runs on windows.
Author
NoRelect
Attachments
dino-configurator.tar.gzSolution
It’s a .NET reversing challenge.
Using ILSpy, we can quickly export the code:
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using DinoConfigurator.Properties;
namespace DinoConfigurator
{
public class Form1 : Form
{
private IContainer components;
private Label lblUsername;
private TextBox txtUsername;
private TextBox txtPassword;
private Label label1;
private Button btnLogin;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnLogin_Click(object sender, EventArgs e)
{
string text = ((Control)txtUsername).get_Text();
string text2 = ((Control)txtPassword).get_Text();
((Control)btnLogin).set_Enabled(false);
((Control)txtUsername).set_Enabled(false);
((Control)txtPassword).set_Enabled(false);
if (Verifier.ValidateUser(text, text2))
{
byte[] cipher = new byte[48]
{
36, 88, 62, 118, 95, 27, 184, 109, 197, 203,
174, 99, 161, 147, 15, 218, 124, 44, 246, 37,
66, 31, 189, 75, 235, 13, 198, 243, 64, 85,
39, 120, 214, 3, 107, 52, 129, 90, 167, 204,
251, 229, 178, 219, 181, 209, 30, 1
};
string text3 = CryptoUtils.Decrypt("908194288470cb5d", cipher, text2);
MessageBox.Show("In reality, I have created this login prompt to hide that I haven't yet fully implemented the app.\nTake this flag in the meantime:\n\n" + text3, "Under construction", (MessageBoxButtons)0);
}
else
{
MessageBox.Show("Invalid username/password. Try again.", "Error", (MessageBoxButtons)0);
}
((Control)btnLogin).set_Enabled(true);
((Control)txtUsername).set_Enabled(true);
((Control)txtPassword).set_Enabled(true);
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
((Form)this).Dispose(disposing);
}
private void InitializeComponent()
{
lblUsername = new Label();
txtUsername = new TextBox();
txtPassword = new TextBox();
label1 = new Label();
btnLogin = new Button();
((Control)this).SuspendLayout();
((Control)lblUsername).set_AutoSize(true);
((Control)lblUsername).set_Location(new Point(12, 9));
((Control)lblUsername).set_Name("lblUsername");
((Control)lblUsername).set_Size(new Size(58, 13));
((Control)lblUsername).set_TabIndex(0);
((Control)lblUsername).set_Text("Username:");
((Control)txtUsername).set_Location(new Point(15, 25));
((Control)txtUsername).set_Name("txtUsername");
((Control)txtUsername).set_Size(new Size(200, 20));
((Control)txtUsername).set_TabIndex(1);
((Control)txtPassword).set_Location(new Point(15, 64));
((Control)txtPassword).set_Name("txtPassword");
((Control)txtPassword).set_Size(new Size(200, 20));
((Control)txtPassword).set_TabIndex(3);
txtPassword.set_UseSystemPasswordChar(true);
((Control)label1).set_AutoSize(true);
((Control)label1).set_Location(new Point(12, 48));
((Control)label1).set_Name("label1");
((Control)label1).set_Size(new Size(56, 13));
((Control)label1).set_TabIndex(2);
((Control)label1).set_Text("Password:");
((Control)btnLogin).set_Location(new Point(140, 90));
((Control)btnLogin).set_Name("btnLogin");
((Control)btnLogin).set_Size(new Size(75, 23));
((Control)btnLogin).set_TabIndex(4);
((Control)btnLogin).set_Text("Login");
((ButtonBase)btnLogin).set_UseVisualStyleBackColor(true);
((Control)btnLogin).add_Click((EventHandler)btnLogin_Click);
((ContainerControl)this).set_AutoScaleDimensions(new SizeF(6f, 13f));
((ContainerControl)this).set_AutoScaleMode((AutoScaleMode)1);
((Control)this).set_BackgroundImage((Image)Resources.matteo_discardi_tdA2J1uJHew_unsplash);
((Control)this).set_BackgroundImageLayout((ImageLayout)4);
((Form)this).set_ClientSize(new Size(800, 450));
((Control)this).get_Controls().Add((Control)(object)btnLogin);
((Control)this).get_Controls().Add((Control)(object)txtPassword);
((Control)this).get_Controls().Add((Control)(object)label1);
((Control)this).get_Controls().Add((Control)(object)txtUsername);
((Control)this).get_Controls().Add((Control)(object)lblUsername);
((Control)this).set_Name("Form1");
((Form)this).set_ShowIcon(false);
((Control)this).set_Text("Dino Configurator");
((Form)this).add_Load((EventHandler)Form1_Load);
((Control)this).ResumeLayout(false);
((Control)this).PerformLayout();
}
}
internal static class Program
{
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run((Form)(object)new Form1());
}
}
internal class CryptoUtils
{
internal static bool VerifySecret(int seed, string input, byte[] secret)
{
if (input.Length != secret.Length)
{
return false;
}
Bitmap matteo_discardi_tdA2J1uJHew_unsplash = Resources.matteo_discardi_tdA2J1uJHew_unsplash;
Random random = new Random(seed);
bool result = true;
for (int i = 0; i < secret.Length; i++)
{
Color pixel = Resources.matteo_discardi_tdA2J1uJHew_unsplash.GetPixel(random.Next(matteo_discardi_tdA2J1uJHew_unsplash.Width), random.Next(matteo_discardi_tdA2J1uJHew_unsplash.Height));
byte b = (byte)(pixel.R ^ pixel.G ^ pixel.B ^ pixel.A ^ random.Next(255));
if (((byte)input[i] ^ b) != secret[i])
{
result = false;
}
}
return result;
}
internal static string Decrypt(string iv, byte[] cipher, string key)
{
Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.IV = Encoding.UTF8.GetBytes(iv);
aes.Key = Encoding.UTF8.GetBytes(key);
ICryptoTransform cryptoTransform = aes.CreateDecryptor();
return Encoding.UTF8.GetString(cryptoTransform.TransformFinalBlock(cipher, 0, cipher.Length));
}
}
internal class Random
{
private const uint Multiplier = 1664525u;
private const uint Increment = 1013904223u;
private uint _state;
public Random(int seed)
{
_state = (uint)seed;
}
public Random(uint seed)
{
_state = seed;
}
public uint NextUInt()
{
_state = 1664525 * _state + 1013904223;
return _state;
}
public int Next(int maxValue)
{
if (maxValue <= 0)
{
throw new ArgumentOutOfRangeException("maxValue", "maxValue must be positive.");
}
return (int)(NextUInt() % (uint)maxValue);
}
public double NextDouble()
{
return (double)NextUInt() / 4294967296.0;
}
}
internal class Verifier
{
internal static bool ValidateUser(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
return false;
}
if (!CryptoUtils.VerifySecret(1337, username, new byte[32]
{
185, 118, 150, 153, 92, 18, 192, 188, 152, 183,
200, 123, 254, 68, 171, 145, 173, 83, 187, 49,
199, 190, 40, 112, 204, 0, 24, 101, 120, 103,
118, 166
}))
{
return false;
}
if (!CryptoUtils.VerifySecret(42, password, new byte[32]
{
139, 85, 46, 194, 113, 17, 172, 175, 217, 83,
168, 234, 216, 15, 194, 44, 195, 7, 132, 251,
87, 55, 176, 102, 229, 212, 142, 175, 33, 61,
137, 55
}))
{
return false;
}
return true;
}
}
}
namespace DinoConfigurator.Properties
{
[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[DebuggerNonUserCode]
[CompilerGenerated]
internal class Resources
{
private static ResourceManager resourceMan;
private static CultureInfo resourceCulture;
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static ResourceManager ResourceManager
{
get
{
if (resourceMan == null)
{
resourceMan = new ResourceManager("DinoConfigurator.Properties.Resources", typeof(Resources).Assembly);
}
return resourceMan;
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
internal static Bitmap matteo_discardi_tdA2J1uJHew_unsplash => (Bitmap)ResourceManager.GetObject("matteo-discardi-tdA2J1uJHew-unsplash", resourceCulture);
internal Resources()
{
}
}
[CompilerGenerated]
[GeneratedCode("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed class Settings : ApplicationSettingsBase
{
private static Settings defaultInstance = (Settings)(object)SettingsBase.Synchronized((SettingsBase)(object)new Settings());
public static Settings Default => defaultInstance;
}
}
We can see that the program loads a Bitmap as a key. When I tried to reimplement this using the .NET core runtime, I got errors, so I had to pivot to using Mono to write my script.
Mostly, the challenge is just extracting the PNG file and copy the program functions together. I rewrote the VerifySecret to a getSecret method and simply loaded the PNG from the current directory:
using System;
using System.Drawing;
using System.Security.Cryptography;
using System.Text;
using System.Drawing;
public class Random
{
private const uint Multiplier = 1664525u;
private const uint Increment = 1013904223u;
private uint _state;
public Random(int seed) {
_state = (uint)seed;
}
public Random(uint seed) {
_state = seed;
}
public uint NextUInt() {
_state = 1664525 * _state + 1013904223;
return _state;
}
public int Next(int maxValue) {
return (int)(NextUInt() % (uint)maxValue);
}
public double NextDouble() {
return (double)NextUInt() / 4294967296.0;
}
}
public class Program {
// opposite of VerifySecret
static byte[] getSecret(int seed, byte[] secret) {
Bitmap matteo_discardi_tdA2J1uJHew_unsplash = new Bitmap("./00000018.png");
Random random = new Random(seed);
byte[] input = new byte[secret.Length];;
bool result = true;
for (int i = 0; i < secret.Length; i++) {
Color pixel = matteo_discardi_tdA2J1uJHew_unsplash.GetPixel(random.Next(matteo_discardi_tdA2J1uJHew_unsplash.Width), random.Next(matteo_discardi_tdA2J1uJHew_unsplash.Height));
byte b = (byte)(pixel.R ^ pixel.G ^ pixel.B ^ pixel.A ^ random.Next(255));
input[i] = (byte)(secret[i] ^ b);
}
return input;
}
static string Decrypt(string iv, byte[] cipher, string key) {
Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.IV = Encoding.UTF8.GetBytes(iv);
aes.Key = Encoding.UTF8.GetBytes(key);
ICryptoTransform cryptoTransform = aes.CreateDecryptor();
return Encoding.UTF8.GetString(cryptoTransform.TransformFinalBlock(cipher, 0, cipher.Length));
}
static int Main() {
byte[] cipher = new byte[48]
{
36, 88, 62, 118, 95, 27, 184, 109, 197, 203,
174, 99, 161, 147, 15, 218, 124, 44, 246, 37,
66, 31, 189, 75, 235, 13, 198, 243, 64, 85,
39, 120, 214, 3, 107, 52, 129, 90, 167, 204,
251, 229, 178, 219, 181, 209, 30, 1
};
byte[] flag = getSecret(42, new byte[32]
{
139, 85, 46, 194, 113, 17, 172, 175, 217, 83,
168, 234, 216, 15, 194, 44, 195, 7, 132, 251,
87, 55, 176, 102, 229, 212, 142, 175, 33, 61,
137, 55
});
string dec = Decrypt("908194288470cb5d", cipher, System.Text.Encoding.Default.GetString(flag) );
Console.WriteLine(dec);
return 0;
}
}
mcs Program.cs -pkg:dotnet
./Program.exe
Flag:
dach2026{3asy_d0tn3t_r3v_bcdc578b18b946e5}