Code Puzzle Thread

Discuss Autohotkey related topics here. Not a place to share code.
Forum rules
Discuss Autohotkey related topics here. Not a place to share code.
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

02 Feb 2019, 08:25

Hello jeeswg, I get multiple msgboxes indicating incorrect results in the test script, q::, eg

Code: Select all

put

index: 3

Float

5759439474786304.0

5759438937915392.0

0x14762E00000000

0x14762DE0000000
Cheers.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Code Puzzle Thread

02 Feb 2019, 08:48

- I posted this in the script:
note: when converting from/to Floats,
the fractions could be *fractionally* different,
although the tests show the expected accuracy
- You'll notice that the MsgBoxes only appear for Floats, and that the numbers match to around 7 significant figures.
- Maybe even for that I can find a better fix, but we're talking maths degree level stuff here, and an extensive time commitment.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

03 Feb 2019, 15:36

the tests show the expected accuracy
It is not the correct result for recreating numput.
we're talking maths degree level stuff here
There is hardly any advanced math going on here. The bit manipulations are basic. Your approach requires knowledge about how numbers are stored, so this is not the way I expected the puzzle to be solved. The expected solution would demonstrate a knowledge about the AHK language, not about number formats. Your approach is acceptable, but currently not correctly implemented. I will give you a point for a good effort and good partial solution :clap: . I will give one point to whoever completes jeeswg's solution. I will give two points to whoever completes the full puzzle.

Cheers :wave: .
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Code Puzzle Thread

12 Apr 2019, 15:12

I improved my script, and the MsgBox indicating a slight discrepancy when handling Floats/Doubles now appears less frequently. Around 0.7% of the time versus 24%.

Code: Select all

;slightly improved PuzPut function which handles rounding
;the MsgBox indicating a slight discrepancy now appears less frequently
;before: e.g. 2381/10000 = 0.2381 [24%]
;after: e.g. 67/10000 = 0.0067 [0.7%]

;AHK v2 script
;'PuzGet'/'PuzPut' - recreate NumGet/NumPut functionality
;where 'Puz' refers to 'Code Puzzle Thread'

;note: when converting from/to Floats,
;the fractions could be *fractionally* different,
;although the tests show the expected accuracy

;note: the maths of handling the raw binary data
;of the Floats is very fiddly, so errors are possible

;AHK v2 is used because you can convert from/to Doubles
;by using the address of a variable

w:: ;test PuzPut and PuzGet functions
VarSetCapacity(vData1, 8, 0)
VarSetCapacity(vData2, 8, 0)
NumPut(-12345678, &vData1, "Int")
PuzPut(-12345678, &vData2, "Int")
MsgBox(NumGet(&vData1, "Int"))
MsgBox(NumGet(&vData2, "Int"))
MsgBox(PuzGet(&vData1, "Int"))
return

q:: ;test PuzPut and PuzGet functions
;oType := StrSplit("Char,Short,Int,Int64,Ptr,UChar,UShort,UInt,UInt64,UPtr", ",")
;oType := StrSplit("Char,Short,Int,Int64,Ptr,UChar,UShort,UInt,UInt64,UPtr,Float,Double", ",")
oType := StrSplit("Float,Double", ",")
VarSetCapacity(vData1, 8)
VarSetCapacity(vData2, 8)
vCount := 0
Loop 10000
{
try
{
	vNum := Random(-2147483648, 2147483647)
	vNum *= 256**3
	vTemp := Random(1, oType.Length())
	vType := oType[vTemp]
	NumPut(vNum, &vData1, vType)
	PuzPut(vNum, &vData2, vType)
	vNum1 := NumGet(&vData1, vType)
	vNum2 := NumGet(&vData2, vType)
	vNum1X := PuzGet(&vData1, vType)
	vHex1 := Format("0x{:X}", vNum1)
	vHex2 := Format("0x{:X}", vNum2)
	vHex1X := Format("0x{:X}", vNum1X)
}
catch
	continue
;vCount++
	vIsErr := 0
	;if 0
	if !(vNum1 = vNum2)
	;if !InStr(vType, "Int64")
		MsgBox("put`r`n" "index: " A_Index "`r`n" vType "`r`n" vNum1 "`r`n" vNum2 "`r`n" vHex1 "`r`n" vHex2)
		, vIsErr := 1
	;if 0
	if !(vNum1 = vNum1X)
		MsgBox("get`r`n" "index: " A_Index "`r`n" vType "`r`n" vNum1 "`r`n" vNum1X "`r`n" vHex1 "`r`n" vHex1X)
		, vIsErr := 1
	if vIsErr
		vCount++
}
MsgBox("done " vCount)
return

;==================================================

PuzGet(vAddr, vType:="UPtr")
{
	local
	static oChar, oType := {Char:1, Short:2, Int:4, Int64:8, Ptr:A_PtrSize=8?8:4}
	static vIsReady := 0
	if !vIsReady
	{
		oChar := {0:0}
		VarSetCapacity(vData, 1, 0)
		Loop 255
			PuzPut(A_Index, &vData, "UChar")
			, vOrd := Ord(StrGet(&vData, 1, "CP0"))
			, oChar[vOrd] := A_Index
		vIsReady := 1
	}

	if (vType = "Double")
	{
		vData := 0.0
		memcpy(&vData, vAddr, 8)
		return vData
	}

	if (vType = "Float")
	{
		vNum := PuzGet(vAddr+0, "UInt")
		vSign := !!(vNum & 0x80000000)
		vPow := ((vNum & 0x7F800000) >> 23)
		vNum := vNum & 0x7FFFFF
		if (vPow = 255)
			vPow := 2047
		else if (vPow > 0)
			vPow := (vPow - 127 + 1023)
		;else if (vPow = 0)
		;	vPow := 0
		vNum <<= (52-23)
		vTemp := (vSign ? -0x8000000000000000 : 0) | (vPow << 52) | vNum
		VarSetCapacity(vData, 8)
		PuzPut(vTemp, &vData, "Int64")
		return PuzGet(&vData, "Double")
	}

	vIsSigned := !RegExMatch(vType, "i)^U")
	vSize := oType[RegExReplace(vType, "i)^U")]
	vNum := 0
	Loop vSize
		vNum |= oChar[Ord(StrGet(vAddr+A_Index-1, 1, "CP0"))] << (A_Index*8-8)
	if vIsSigned
		if (vSize = 1) && (vNum >= 128)
			return vNum - 256
		else if (vSize = 2) && (vNum >= 32768)
			return vNum - 65536
		else if (vSize = 4) && (vNum >= 2147483648)
			return vNum - 4294967296
	return vNum
}

PuzPut(vNum, vAddr, vType:="UPtr")
{
	local
	static oChar, oType := {Char:1, Short:2, Int:4, Int64:8, Ptr:A_PtrSize=8?8:4}
	static vIsReady := 0, vDataNull := 0
	if !vIsReady
	{
		;oChar := {0:""}
		oChar := {}
		VarSetCapacity(vDataNull, 1, 0)
		Loop 255
			oChar[A_Index] := Chr(A_Index)
		vIsReady := 1
	}

	if (vType = "Double")
	{
		vData := vNum + 0.0
		memcpy(vAddr, &vData, 8)
		return
	}

	if (vType = "Float")
	{
		vData := vNum + 0.0
		vNum := PuzGet(&vData, "Int64")

		;0x8000000000000000 (UInt64) = 0x8000000000000000 - 0x10000000000000000 (Int64) = -0x8000000000000000 (Int64)
		vSign := !!(vNum & -0x8000000000000000)
		vPow := ((vNum & 0x7FF0000000000000) >> 52)
		vNum := vNum & 0xFFFFFFFFFFFFF

		if (vPow = 2047)
			vPow := 255
		else if (vPow > 0)
			vPow := (vPow - 1023 + 127) & 0xFF
		;else if (vPow = 0)
		;	vPow := 0
		vBit := (vNum >> (52-24)) & 0x1 ;truncate number, but if bit is 1, round up
		vNum >>= (52-23)
;MsgBox vBit
;if (vBit)
;throw
		;handle rounding:
		;if 0
		if vBit
		{
			vTemp := 1
			Loop 22
			{
				if !(vNum & vTemp)
				{
					vNum |= vTemp
					vNum ^= vTemp-1
					break
				}
				vTemp <<= 1
			}
			if (vTemp = 2**22)
				vNum := 0, vPow += 1
		}

		vTemp := (vSign << 31) | (vPow << 23) | vNum
		PuzPut(vTemp, vAddr+0, "UInt")
		return
	}

	vSize := oType[RegExReplace(vType, "i)^U")]
	Loop Min(vSize, 7)
		vTemp := vNum & (0xFF << (A_Index*8-8))
		, vTemp >>= (A_Index*8-8)
		, (vTemp=0) ? memcpy(vAddr+A_Index-1, &vDataNull, 1) : memcpy(vAddr+A_Index-1, oChar.GetAddress(vTemp), 1)
	;0xFF00000000000000 (UInt64) = (0xFF00000000000000 - 0x10000000000000000) (Int64) = -0x100000000000000 (Int64)
	if (vSize = 8)
		vTemp := SubStr(Format("0x{:016X}", vNum & -0x100000000000000), 1, 4)
		, vTemp := Integer(vTemp)
		, (vTemp=0) ? memcpy(vAddr+7, &vDataNull, 1) : memcpy(vAddr+7, oChar.GetAddress(vTemp), 1)
}

memcpy(dest, src, count){
	/*
	void *memcpy(
		void *dest,
		const void *src,
		size_t count
	);
	url: https://msdn.microsoft.com/en-us/library/dswaw1wk.aspx (memcpy)
	*/
	return dllcall("MSVCRT.dll\memcpy", "ptr", dest, "ptr", src, "ptr", count, "cdecl")
}

;prepend Z to MsgBox, and it becomes a NoOp
ZMsgBox(oParams*)
{
}
To explain rounding in binary, here are 2 examples in decimal, where I want to remove the last digit, but since the last digit is 5 or higher, rounding up must be done:

0.999000999
0.99900100

0.999999999
1.00000000

In binary, if the last bit is 1, rounding up must be done. You start at the rightmost bit, and go left until you find a 0 bit, that 0 bit becomes a 1 bit, and the bits after it all become 0 bits.

0.111000111
0.11100100

0.111111111
1.00000000
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

13 Apr 2019, 07:44

I don't see any explanation. Why are you rounding up?
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Code Puzzle Thread

13 Apr 2019, 07:53

When you convert from a double to a float, decreasing precision, you have to round the number. Rounding down is simply truncation, rounding up, which I explained above, involves a bit of bit magic.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

13 Apr 2019, 08:06

When you convert from a double to a float, decreasing precision, you have to round the number.
Why?
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Code Puzzle Thread

13 Apr 2019, 08:30

- In my script, I take advantage of the fact that AutoHotkey natively uses doubles. I need to convert those doubles to floats. So the question is: how do you convert a double to a float.
- What you need to do is take the 3 numbers: sign, exponent, significand, and adjust them to decrease the precision, AFAIK this involves rounding. Initially I was only rounding down, and the script was getting around 50% of the conversions slightly mismatched. When I started handling rounding up, that figure was more like 1%.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

13 Apr 2019, 08:44

So the question is: how do you convert a double to a float.
Initially I was only rounding down, and the script was getting around 50% of the conversions slightly mismatched. When I started handling rounding up, that figure was more like 1%.
So you should conclude that either, rounding up isn't the answer, or you are doing it wrong, or both.
User avatar
jeeswg
Posts: 6904
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Code Puzzle Thread

13 Apr 2019, 09:01

- The only thing I can conclude currently is that: the floats/doubles have not always been matching up exactly. I cannot even conclude that they *should* always be matching up exactly.
- If by training or by experimentation you have something to add on the matter, I would suggest you do so, either by clue, or just by giving a complete answer.
- I have limited time, and over the next few days I will be completing some mathematical tutorials, so any input would be better now rather than later.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Evil-e
Posts: 108
Joined: 04 Sep 2018, 11:09

Re: Code Puzzle Thread

20 Apr 2019, 05:01

Oh my god.... you pepes are soooooooooooo far over my head with all this code. After looking at some of the posts,
I am not even sure 1+1=2 anymore.... does it?
I have a bit of experience opening and sending commands to game console and CMD.exe... just ask :)
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

28 Jun 2019, 08:15

Puzzle 12 - Not a regular bank heist

Puzzle description: You are a customer at a bank for wealthy people only, unfortunately, you made some bad business and are now broke. But there is some good news, you are skilled hacker and have managed to hack part of the bank's user interface and software. You now see your chance to get all the money, and get away with it!

Puzzle objectives:In this puzzle, you will study the bank software, then write a script which automates the user interface to transfer all the wealthy bank customer's money to your account and then clear the bank's internal logs to cover your tracks. When you run the bank software, you are logged in to your account. (Your name is Jane). When you have achieved the task, you account balance will be $12081334876 and you will be able to log out from the bank without alerting the police.

Puzzle rules: You can not modify the script below, you are only allowed to write a new script which automates the bank's user interface. No low level process memory or file manipulation is allowed. The script doesn't need to be completely automatic, but should be easy to use and come with clear instructions if needed.

The bank software:

Code: Select all

;
; You are not allowed to edit this code in any way:
;
; logged in details:
global logged_in_id := 16
global logged_in_name := "Jane"
; Transaction related:
global global_amount := 0			; The amount to transfer in the next transaction
global transfer_log := []			; Initialise transfer log

; Load account data:
global account_id_balance_map := [ 4840409, 6381577, 2136819, 3943104, 4877043, 44329046, 21340236, 10591744, 33157912, 5271471, 5459720666, 611417736, 153238799, 113762642, 5606323672, 2000]

global account_name_id_map :=	{ 	 Jimmy 		: 1,	Rosalynn 		: 2
									,Ronald		: 3, 	Nancy			: 4
									,George 	: 5,	Barbara			: 6
									,Bill 		: 7, 	Hillary			: 8,	Monica : 9
									,Georgew	: 10, 	Laura			: 11
									,Barack		: 12, 	Michelle		: 13
									,Donald 	: 14, 	Melania			: 15
									,(logged_in_name) : logged_in_id }



; UI:
global show_warning := true 		; default setting, show warning when incorrect password provided.
global bank_name := "Secure bank"	; The name of the bank
create_login_screen()				; Create the user interface
gui show,, % bank_name				; show the user interface

;
;	Bank software:
;

login(account_name, password) {
	static min_pw_len := 8
	if (strlen(password) < min_pw_len				; verify password is at least min_pw_len long.
		|| account_name ~= "i)\Q" . password . "\E" ; verify that the password isn't contained in the account_name to avoid calling verifyPassword with invalid password.
		|| !verifyPassword(account_name, password)) {
		if show_warning
			msgbox % 0x10,  % bank_name, % "Invalid password for account_name: " . account_name
		return 0
	}
	; Logged in successfully!
	
	logged_in_id := account_name_to_id(account_name)	; set the logged in account.
	logged_in_name := account_name
	
	; Update gui:
	gui_update_logged_in()
}

account_name_to_id(name_to_find) {
	for acc_name, id in account_name_id_map
		if (acc_name = name_to_find)
			return id
	return 0
}

transfer(source_account_name, dest_account_id) {
	; Verify input:
	if account_name_id_map.haskey(source_account_name)
		source_account_id := account_name_id_map[source_account_name]
	else {
		msgbox % 0x10,  % bank_name, % "Invalid source account: " source_account_name
		return false
	}
	if !account_id_balance_map.haskey(dest_account_id) || dest_account_id == source_account_id {
		msgbox % 0x10,  % bank_name, % "Invalid destination account: " dest_account_id
		return false
	}
	; All verified, do the transaction
	amount_to_transfer := global_amount == -1 ? account_id_balance_map[source_account_id] : global_amount 	; determine the amount to transfer.
	if (amount_to_transfer < 0) 
		return false
	
	if (amount_to_transfer > account_id_balance_map[source_account_id])
		return false
	
	account_id_balance_map[source_account_id] -= amount_to_transfer											; decrement source account balance.
	account_id_balance_map[dest_account_id] += amount_to_transfer											; increment destination account balance.
	; Log transfer
	log_handler("append", a_now .  "`n" . dest_account_id .  "`n" . source_account_id .  "`n" . amount_to_transfer)
	gui_refreshBalance(logged_in_id)	; Update the user interface to reflect the transaction.
	return true
}

log_handler(mode, what := 0) {
	; Handles the log of transactions
	; mode, string, one of:
	;	- append, append the log
	;	- verify_exit, verify the log is empty before logout
	;	- clear, clear items from the log, only done the relevant items has been verified.
	; what, string or integer, an item to log, or an integer defining the amount of logged items to clear, from the start of the log.
	if (mode == "append") {
		transfer_log.push(str)
	} else if (mode == "verify_exit") {
		; at this stage all transfers must have been verified elsewhere and removed from the transfer_log.
		if (transfer_log.length())
			return false
		; verified!
	} else if (mode == "clear") {
		if transfer_log.length() {
			if (what > transfer_log.length() || what < 1)
				throw exception("Invalid use")
			transfer_log.removeat(1, what)
		}
	}
	return true
}

;
;	User interface:
;

create_login_screen() {
	gui new
	gui add, tab3, , Login|Account|Transfer|Options|Log out
	gui add, text,, Account name:
	gui add, edit, w300
	gui add, text,, password:
	gui add, edit, w300 password
	gui add, button, w300 ggui_login, Login
	gui tab, Account
	gui add, text, w300, % "Account balance:`t$" . account_id_balance_map[logged_in_id]
	gui add, text, w300, Account name:`t%logged_in_name%
	gui add, text, w300, Account id:`t%logged_in_id%
	gui tab, Transfer
	gui add, text,, Amount:
	gui add, edit, w300, 0
	gui add, text,, To acount name:
	gui add, edit, w300
	gui add, checkbox, checked0, Transfer all.
	gui add, button, w300 ggui_transfer, Transfer
	gui tab, Options
	gui add, checkbox, checked1 gtoggle_warning, Show login warnings.
	gui tab, Log out
	gui add, button, w300 ggui_logout, Login out
}
gui_transfer() {
	
	guicontrolget amount_to_transfer,, Edit3
	guicontrolget to_account_name,, Edit4
	guicontrolget transfer_all,, Button2
	global_amount := transfer_all ? -1 : amount_to_transfer
	to_account_id := account_name_id_map[to_account_name]
	transfer(logged_in_name, to_account_id)
}
gui_update_logged_in() {
	guicontrol,, Static3, % "Account balance:`t$" . account_id_balance_map[logged_in_id]
	guicontrol,, Static4, Account name:`t%logged_in_name%
	guicontrol,, Static5, Account id:`t%logged_in_id%
}
gui_login() {
	guicontrolget account_name,, Edit1
	guicontrolget password,, Edit2
	login(account_name, password)
}
guiescape(){
	gui_logout()
}
guiclose(){
	gui_logout()
}

gui_logout() {
	if !log_handler("verify_exit")
		msgbox % "Suspicious transfers detected, police has been contacted."
	else
		msgbox % "Log out successful, welcome back soon."
	exitapp
}
gui_refreshBalance(id) {
	guicontrol,, Static3, % "Account balance:`t$" . account_id_balance_map[id]
}

toggle_warning(){
	show_warning := !show_warning
}

; Black box
verifyPassword(acc, pw){
	return false
}

New rule: for the first month, please only submit your solution to me via PM so that more people get the chance to try it out before the solution is made public. The first one to solve it gets two points, everyone else within the first month gets one point.

One month from now is the first of August.

Cheers and good luck.
User avatar
TheDewd
Posts: 1352
Joined: 19 Dec 2013, 11:16
Location: USA

Re: Code Puzzle Thread

01 Jul 2019, 12:57

Puzzle 12 - Not a regular bank heist
Do passwords exist for the accounts? :crazy: Ha, this is hard to figure out! Quite challenging.
Image Bulldozer - Sokoban inspired game from 1994 recreated in AutoHotkey.
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

01 Jul 2019, 13:26

puzzle 12 wrote:

Code: Select all

; Black box
verifyPassword(acc, pw){
	return false
}
Hehe, you can try any password you like, it will not be verified, but the puzzle can be solved ;)
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

03 Jul 2019, 02:24

I'm happy to announce that we have a winner for Puzzle 12, CloakerSmoker has submitted an excellent solution to the puzzle and will be awarded two points. Everyone else are still welcome to submit their solutions to me via PM before the first of august, for that you will recieve one point and eternal glory. The solution will be made public on the first of august or short there after.

Cheers.
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

07 Aug 2019, 03:13

Here is the solution for puzzle 12, please follow the instructions:
  • Start the :arrow: bank script.
  • Goto Options and uncheck the checkbox to disable login warnings.
  • Goto Transfer and check the Transfer all checkbox, then hit the Transfer button and dismiss the MsgBox.
  • Start the solution script given below.
  • Goto the Login tab in the bank script, and select the top-most edit field, Account Name.
  • Press ctrl + 1 to start the automatic process. (Press Esc to abort)
  • Wait until the MsgBox says Done!. (Takes a few seconds)
  • Goto Account to check your balance, then logout.
Solution script: edit, backup your clipboard before using, if needed.

Code: Select all

; How to:
; Disable warnings in options
; make invalid transfer with transfer all checkbox ticked
; select user name field in login tab.
; press ^1.
#warn all

global logged_in_id := 16

global account_name_id_map :=	{ 	 Jimmy 		: 1,	Rosalynn 		: 2
									,Ronald		: 3, 	Nancy			: 4
									,George 	: 5,	Barbara			: 6
									,Bill 		: 7, 	Hillary			: 8,	Monica : 9
									,Georgew	: 10, 	Laura			: 11
									,Barack		: 12, 	Michelle		: 13
									,Donald 	: 14, 	Melania			: 15 }
transfers := []
for name in account_name_id_map {
	
	transfers.push(name)
	password := "\E" . name . "(?C" . logged_in_id . ":transfer)\Q"
	transfers.push(password)
	
}
transfers.push("clear")
transfers.push("\Eclear(?C15:log_handler)\Q")

^1::
	setkeydelay 10, 1
	while transfers.length() {
		; account name and password:
		loop 2 {
			clipboard := ""
			clipboard := transfers.removeat(1)
			clipwait 1
			send ^a^v	; overwrite field
			send {tab}	; go to next field or log in button
		}
		
		send {enter} 	; hit log in button
		send +{tab 2} 	; go back to account field
	}
Msgbox "Done!"
~esc::exitapp
Study the code to find out how the exploit works.

Cheers.
rommmcek
Posts: 730
Joined: 15 Aug 2014, 15:18

Re: Code Puzzle Thread

08 Aug 2019, 14:53

So the Bank softer bug is "i)\Q" . password . "\E"??? (should be \E....\Q?), allowing injection of commands.
Automatization of the solution is not the very best. Quicker and more reliable alternative in appendage.

But I still do not get it. If the hacker is allowed to copy paste part of the software, why I can't include the whole code and do the heck I want. Improved version in attachement.

bye!
Attachments
Hack Secure Bank.zip
(4.15 KiB) Downloaded 24 times
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

09 Aug 2019, 03:59

Hi @rommmcek :wave: .
So the Bank softer bug is "i)\Q" . password . "\E"??? (should be \E....\Q?),
No, the bank software should not be \E...\Q. There is no bug in the software per se, just a vulnerability which a hacker can exploit.
why I can't include the whole code and do the heck I want
You can include the whole code in your solution script as long as it automates the gui of the running unaltered bank script, that is, two scripts needs to be running. It is a game, you should pretend you actually interact with the bank's program, not running a disconnected program on your local machine, otherwise you could just do a script like this,

Code: Select all

account_id_balance_map := [0, 0, ..., 12081334876] ; Done!
That's not very fun.

Writing a perfect automation script wasn't part of the challenge. As stated, semi-automatic was acceptable.

Cheers.
lexikos
Posts: 6668
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Code Puzzle Thread

10 Aug 2019, 03:24

A bit late, but I wonder if Puzzle 11 required memcpy be called only via the given wrapper? This seems to satisfy jeeswg's test cases:

Code: Select all

PuzGet(Addr, Type := "UPtr") {
    DllCall("msvcrt.dll\memcpy", Type "*", result, "ptr", Addr, "ptr", PuzSz(Type), "cdecl")
    return result
}

PuzPut(Num, Addr, Type:="UPtr") {
    DllCall("msvcrt.dll\memcpy", "ptr", Addr, Type "*", Num, "ptr", PuzSz(Type), "cdecl")
}

PuzSz(Type) {
    return {Char:1,Int:4,Int64:8,Short:2,UChar:1,UInt:4,UInt64:8,UShort:2,Float:4,Double:8}[Type]
}
Helgef
Posts: 4031
Joined: 17 Jul 2016, 01:02
Contact:

Re: Code Puzzle Thread

10 Aug 2019, 07:29

Well done lexikos, glad to see you participate :thumbup:
I wonder if Puzzle 11 required memcpy be called only via the given wrapper?
That was my intention but it seems I didn't clearly convey that in the puzzle rules, so due to that and due to your solution being similar, in principle, to what I had intended, I accept your solution.

Requiring use of the wrapper function would make it a little more complicated but ultimately, using dllcall's type* was the most important part I wanted you (all) to find. Here is what I had in mind, for v2 (pre-bufferalloc),

Code: Select all

_numput(number, dest, o := 0, type := 'uptr'){
	static types :=	{ char	: 1, uchar 	: 1, short	: 2, ushort : 2, int		: 4, uint 	: 4, ptr		: a_ptrsize, uptr	: a_ptrsize,float : 4, double : 8 }
	local
	put number, dest + o, type, types[ type ]
	return dest + o + types[ type ]
	put(val, dest, type, count){
		static cb := callbackcreate( (dest, src, count) => memcpy(dest, src, count) )
		dllcall(cb, 'ptr', dest, type . '*', val, 'ptr', count)
	}
}
_numget(src, o := 0, type := 'uptr'){
	static types :=	{ char	: 1, uchar 	: 1, short	: 2, ushort : 2, int		: 4, uint 	: 4, ptr		: a_ptrsize, uptr	: a_ptrsize,float : 4, double : 8 }
	local
	varsetcapacity dest, 8, 0
	memcpy &dest, src + o, types[ type ]
	return get(dest, type)
	get(byref addr, type){
		static cb := callbackcreate( p => p )
		return dllcall(cb, 'ptr', &addr, type . '*')
	}
}
For v1 you'd use registercallback + non-nested help functions.

Cheers.

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 11 guests