REVERSE-PRACTICE-BUUCTF-10
[GWCTF 2019] xxor
arquivo elf, sem shell,
lógica clara de análise da função principal com ida , primeiro obtenha a entrada, que é 6 valores int64, a seguir, a cada 2 valores são definidos, chame a função sub_400686 para transformar, o valor transformado é armazenado em v11, e finalmente verificou v11, verifique a
função de entrada sub_400686, leia os 2 valores de cada grupo, execute 64 ciclos e coloque o valor transformado de volta na posição original. A
função de verificação pode ser usada para obter os 6 valores que precisa ser alterado após a transformação da entrada.
Escreva o script inverso, os 6 valores de v11 podem ser calculados manualmente ou usando a biblioteca z3 do python para calcular o
tipo v5 como int32, o valor inicial é 0, 64 adições devem exceder o máximo valor positivo de int32, mas será interceptado automaticamente durante o processo de cálculo, portanto, não há necessidade de considerar v5 especial, basta escrever o script normalmente
#include<stdio.h>
__int64 v11[] = {
0xdf48ef7e,0x20caacf4,0xe0f30fd5,
0x5c50d8d6,0x9e1bde2d,0x84f30420 };
__int64 a2[] = {
2,2,3,4 };
void main()
{
for (int i = 0; i <= 4; i += 2)
{
unsigned int v3 = v11[i];
unsigned int v4 = v11[i + 1];
int v5 = 0;
for (int j = 0; j <= 63; j++)
v5 += 1166789954;
for (int j = 0; j <= 63; j++)
{
v4-= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
v3-= (v4 + v5 + 11) ^ ((v4 << 6) + a2[0]) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
v5 -= 1166789954;
}
if (v5 == 0)
{
v11[i] = v3;
v11[i + 1] = v4;
}
}
for (int i = 0; i < 6; i++)
{
printf("%ld,", v11[i]);
}
}
Execute o resultado e, em
seguida, use long_to_bytes do python para converter em uma string
[HDCTF2019] Labirinto
exe programa, após a execução, ele pede para obter a bandeira através do labirinto, há um shell upx, após ida analisa a
função principal não é reconhecida como uma função por ida, a razão é que a instrução de flor
jnz é adicionada ao código para pular para a próxima instrução. Uma instrução em que jnz impede o reconhecimento de ida, você precisa
interromper toda a instrução de jnz. No texto: 0040102E, um endereço vermelho é chamado, indicando que o endereço vermelho não existe no programa , deve estar no byte de instrução correto Com base na adição de alguns bytes, ele se torna irreconhecível por ida, então você precisa remover os bytes extras, selecionar o endereço vermelho, pressionar d para converter em dados e, em seguida, nop e solte alguns bytes para ver se ida pode ser capaz de, após nop, descartar os bytes Reconhecidos como código, e descobriu que depois de converter para dados, nop descarta o primeiro byte e ida pode reconhecer o
efeito de remover a instrução de flor.
Selecione o .texto vermelho codifique do início da função principal ao final da instrução retn, e pressione p para gerar a função. F5 descompilação
Analisa a função principal, wsad corresponde ao topo, base, esquerda e direita, a posição inicial é [7 , 0], e a posição final é [5, -4].
Encontre o mapa do labirinto na janela da string, o comprimento é 70 e a estimativa é 10x7 ou 7x10. A posição inicial e a posição final podem ser conhecidas, o o mapa é 7x10, ou seja, 7 linhas e 10 colunas, o ponto inicial está em "+" e o ponto final está em "F". Você pode pegar a bandeira depois de caminhar pelo labirinto.
[WUSTCTF2020] nível 2
arquivo elf, com upx shell, análise ida após o shell.
Encontre a função principal na janela de funções à esquerda e você pode ver o sinalizador na janela IDA View-A
[BJDCTF2020] Competição de hambúrguer BJD
Unidade jogo, a idade de oito segredo pequeno hambúrguer,
adicione os ingredientes na ordem correta para obter a bandeira BJD hambúrguer competition_Data-> Managed-> Assembleia-CSharp.dll arrastar em dnSpy para
encontrar a parte da lógica principal. O
método MD5 md5 os parâmetros de entrada. Coluna, maiúsculas, pegam os primeiros 20 dígitos. O
método Sha1 realiza hash sha1 nos parâmetros de entrada. O
método Spawn em maiúsculas verifica a ordem de alimentação. Ingredientes diferentes são selecionados para realizar operações diferentes em Init.secret (o o valor inicial é 0). O resultado do hash sha1 é comparado com o valor conhecido, quando o mesmo, o programa irá hash o resultado da operação md5 e emitirá como flag
using System;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
// Token: 0x02000004 RID: 4
public class ButtonSpawnFruit : MonoBehaviour
{
// Token: 0x0600000A RID: 10 RVA: 0x00002110 File Offset: 0x00000310
public static string Md5(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] array = MD5.Create().ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
foreach (byte b in array)
{
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString().Substring(0, 20);
}
// Token: 0x0600000B RID: 11 RVA: 0x00002170 File Offset: 0x00000370
public static string Sha1(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
byte[] array = SHA1.Create().ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
foreach (byte b in array)
{
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString();
}
// Token: 0x0600000C RID: 12 RVA: 0x000021C8 File Offset: 0x000003C8
public void Spawn()
{
FruitSpawner component = GameObject.FindWithTag("GameController").GetComponent<FruitSpawner>();
if (component)
{
if (this.audioSources.Length != 0)
{
this.audioSources[Random.Range(0, this.audioSources.Length)].Play();
}
component.Spawn(this.toSpawn);
string name = this.toSpawn.name;
if (name == "汉堡底" && Init.spawnCount == 0)
{
Init.secret += 997;
}
else if (name == "鸭屁股")
{
Init.secret -= 127;
}
else if (name == "胡罗贝")
{
Init.secret *= 3;
}
else if (name == "臭豆腐")
{
Init.secret ^= 18;
}
else if (name == "俘虏")
{
Init.secret += 29;
}
else if (name == "白拆")
{
Init.secret -= 47;
}
else if (name == "美汁汁")
{
Init.secret *= 5;
}
else if (name == "柠檬")
{
Init.secret ^= 87;
}
else if (name == "汉堡顶" && Init.spawnCount == 5)
{
Init.secret ^= 127;
string str = Init.secret.ToString();
if (ButtonSpawnFruit.Sha1(str) == "DD01903921EA24941C26A48F2CEC24E0BB0E8CC7")
{
this.result = "BJDCTF{" + ButtonSpawnFruit.Md5(str) + "}";
Debug.Log(this.result);
}
}
Init.spawnCount++;
Debug.Log(Init.secret);
Debug.Log(Init.spawnCount);
}
}
// Token: 0x04000005 RID: 5
public GameObject toSpawn;
// Token: 0x04000006 RID: 6
public int spawnCount = 1;
// Token: 0x04000007 RID: 7
public AudioSource[] audioSources;
// Token: 0x04000008 RID: 8
public string result = "";
}
Use o site online para resolver o valor original do sha1 conhecido. Se for 1001
, md5 o 1001, converta em maiúsculas e
use os primeiros 20 dígitos para obter a bandeira. Se você não usar o site online para resolver os hashes sha1 e md5, escreva um script explosivo
#coding:utf-8
#汉堡底 +=997
#汉堡顶 ^=127
#鸭屁股 -=127 0
#胡罗贝 *=3 1
#臭豆腐 ^=18 2
#俘虏 +=29 3
#白拆 -=47 4
#美汁汁 *=5 5
#柠檬 ^=87 6
import hashlib
#从其他7种材料中选4种 加上汉堡底和汉堡顶 一共6种
for i in range(7):
for j in range(7):
for k in range(7):
for m in range(7):
secret=997 #汉堡底当作第一种材料
if i==0:
secret-=127
elif i==1:
secret*=3
elif i==2:
secret^=18
elif i==3:
secret+=29
elif i==4:
secret-=47
elif i==5:
secret*=5
elif i==6:
secret^=87
if j==0:
secret-=127
elif j==1:
secret*=3
elif j==2:
secret^=18
elif j==3:
secret+=29
elif j==4:
secret-=47
elif j==5:
secret*=5
elif j==6:
secret^=87
if k==0:
secret-=127
elif k==1:
secret*=3
elif k==2:
secret^=18
elif k==3:
secret+=29
elif k==4:
secret-=47
elif k==5:
secret*=5
elif k==6:
secret^=87
if m == 0:
secret -= 127
elif m == 1:
secret *= 3
elif m == 2:
secret ^= 18
elif m == 3:
secret += 29
elif m == 4:
secret -= 47
elif m == 5:
secret *= 5
elif m == 6:
secret ^= 87
secret^=127 #最后加汉堡顶的时候,材料的种数还没有加到6
h = hashlib.sha1()
h.update(str(secret).encode(encoding='utf-8'))
#验证sha1散列
if h.hexdigest() == "DD01903921EA24941C26A48F2CEC24E0BB0E8CC7".lower():
print(secret)
#输出md5散列
h2 = hashlib.md5()
h2.update(str(secret).encode(encoding='utf-8'))
print(h2.hexdigest().upper()[0:20])
resultado da operação