๋ฌธ์ : DreamHack โ [CodeEngn] Malware L03 ๋ถ๋ฅ: Misc (์ ์ฑ์ฝ๋ ๋ถ์) ๋์ด๋: ๐ฅ Bronze 1 FLAG:
checksum
๋ฐฐํฌ ํ์ผ์ ํ ์คํธ ํ ์ฅ์ด๊ณ , ๋ฌธ์ ์ค๋ช ์ ๋ ์ค์ด๋ค.
# show_desc.sh
#!/bin/sh
# ๋๋ฆผํต API ์์ ์ด ๋ฌธ์ ์ ์ ๋ชฉยท๋ถ๋ฅยท์ค๋ช
๋ง ๋ฝ์ ๋ณธ๋ค
python3 ~/Dev/Hacking_Project/_๋๊ตฌ/dreamhack_auto/fetch_desc.py 370 | python3 -c '
import sys, json
d = json.load(sys.stdin)
print("์ ๋ชฉ :", d["title"].strip())
print("๋ถ๋ฅ :", ", ".join(d["tags"]))
print("๋์ด๋ :", d["tier_display"])
print("ํผ ์ฌ๋ :", d["cnt_solvers"], "๋ช
")
print()
print("[๋ฌธ์ ์ค๋ช
]")
print(d["description"].strip())
print()
print("[ํํธ]", d["hints"] or "์์")
'./show_desc.sh
ex) ์์์กฐ์ฐจ ์๊ณ ํํธ๋ ์๋ค. ๊ฐ์ ์๋ฆฌ์ฆ Malware L02์ ํ์์ ๊ฐ๋ค โ ์๋ฌธ์ ํ ๋จ์ด, ๋์ด์ฐ๊ธฐ ์์ด.
๋ฌธ์ ๊ฐ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| ๋ฌธ์ ๋ช | [CodeEngn] Malware L03 (DreamHack #370) |
| ๋์ด๋ | ๐ฅ Bronze 1 |
| ๋ถ๋ฅ | Misc โ ์ ์ฑ์ฝ๋ ์์ค ๋ถ์ |
| ์ ๊ณต ํ์ผ | 03.txt (308๋ฐ์ดํธ, 10์ค, CRLF) |
| ์๋ฒ | ์์ (์คํ๋ผ์ธ ๋ฌธ์ ) |
| ํต์ฌ | RFC 1071 ์ธํฐ๋ท ์ฒดํฌ์ฌ โ ๋ก์ฐ์์ผ์ผ๋ก ํค๋๋ฅผ ์ง์ ๋ง๋๋ ์ฝ๋๊ฐ ์ปค๋ ๋์ ์ฑ์์ผ ํ๋ ๊ฐ |
ํ์ด ํ๋ฆ์ ๋จ์ํ๋ค. ์ฝ๋๋ฅผ ์ฝ๊ณ "์ฒดํฌ์ฌ ๊ฐ๋ค"๊น์ง๋ ๊ธ๋ฐฉ ๊ฐ๋ค. ๋ฌธ์ ๋ ๊ทธ๋ค์์ด๋ค. ์ด๋ค ์ฒดํฌ์ฌ์ธ์ง, ๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ ์ ๋ง ๋ง๋์ง๋ฅผ ๋ฌด์์ผ๋ก ํ์ ํ๋๋. ์ด ๊ธ์ ๊ทธ ํ์ ๊ณผ์ ์ด ์ ๋ถ๋ค.
๐ฌ ์ ์ฐฐ โ ๋ฐฐํฌ๋ณธ์ 10์ค์ด ์ ๋ถ๋ค
file extracted/03.txt; wc -lc extracted/03.txt; sha256sum extracted/03.txt; cat extracted/03.txt
๋ฐฐํฌ๋ณธ ์ ๋ฌธ์ ์ด๋ ๋ค.
u_short Malware_L03(u_short * data,u_short length)
{
register long value;
u_short i;
for(i=0;i<(length>>1);i++)
value+=data[i];
if((length&1)==1)
value+=(data[i]<<8);
value=(value&65535)+(value>>16);
return(~value);
}์ฝํ๋ ๋๋ก ์ฎ๊ธฐ๋ฉด ์ด๋ ๊ฒ ๋๋ค.
data๋ฅผ 16๋นํธ ์๋ ๋ฐฐ์ด๋ก ๋ณด๊ณlength>>1๊ฐ๋ฅผvalue์ ๋ํ๋ค.- ๊ธธ์ด๊ฐ ํ์๋ฉด ๋จ์ ์๋ฆฌ๋ฅผ
data[i]<<8๋ก ํ ๋ฒ ๋ ๋ํ๋ค. (value&65535)+(value>>16)์ผ๋ก ์์๋ก ๋์น ์บ๋ฆฌ๋ฅผ ํ์ 16๋นํธ์ ๋๋๋ ค ๋ํ๋ค.- ๋ง์ง๋ง์
~value๋ฅผ 16๋นํธ๋ก ์๋ผ ๋ฐํํ๋ค.
์บ๋ฆฌ๋ฅผ ๋ฒ๋ฆฌ์ง ์๊ณ ๋๋๋ ค ๋ํ๋ ๋ง์ , ๊ทธ๋ฆฌ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์๋ก ๋ค์ง์ด ๋ด๋ณด๋ด๋ ๋ง๋ฌด๋ฆฌ. ์ด ์กฐํฉ์ 1์ ๋ณด์ ํฉ, ์ฆ ์ธํฐ๋ท ์ฒดํฌ์ฌ์ ์ง๋ฌธ์ด๋ค. ๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ๊น์ง๋ "๊ทธ๋ ๊ฒ ์๊ฒผ๋ค"๋ ๊ด์ฐฐ์ผ ๋ฟ์ด๋ค. CRC ๊ณ์ด๋, ๋จ์ ํฉ๊ณ๋ ๊ฒ๋ชจ์ต์ ๋น์ทํ๊ฒ ์ธ ์ ์๋ค.
๐งฉ ๋ฐฐ๊ฒฝ โ ์ธํฐ๋ท ์ฒดํฌ์ฌ์ ์ด๋์ ์ฐ์ด๋ ๊ฐ์ธ๊ฐ
IPv4 ํค๋์๋ Header checksum ์ด๋ผ๋ 16๋นํธ ์๋ฆฌ๊ฐ ์๋ค. TCPยทUDPยทICMP ํค๋์๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๊ณ์ฐํ ์ฒดํฌ์ฌ ์๋ฆฌ๊ฐ ํ๋์ฉ ์๋ค.

์ถ์ฒ: Wikimedia Commons, Michel Bakni, CC BY-SA 4.0
๊ณ์ฐ ๊ท์น์ RFC 1071์ ์๋ค. ์์ฝํ๋ฉด ์ธ ์ค์ด๋ค.
- ๋ฐ์ดํฐ๋ฅผ 16๋นํธ ์๋๋ก ๋์ด 1์ ๋ณด์ ํฉ์ ๊ตฌํ๋ค. ๋์น ์บ๋ฆฌ๋ ๋ฒ๋ฆฌ์ง ์๊ณ ํ์๋ก ๋๋๋ ค ๋ํ๋ค.
- ๊ธธ์ด๊ฐ ํ์๋ฉด ๋ง์ง๋ง ๋ฐ์ดํธ ์ค๋ฅธ์ชฝ์ 0์ผ๋ก ์ฑ์ 16๋นํธ ์๋๋ก ๋ง๋ ๋ค.
- ํฉ์ 1์ ๋ณด์๊ฐ ์ฒดํฌ์ฌ์ด๋ค.
์ด ๋ฐฉ์์ด ์ค๋ ์ด์๋จ์ ์ด์ ๋ ์ฑ์ง์ด ๋ ๊ฐ ์์ด์๋ค. ๋ง์ ์ด ๊ตํยท๊ฒฐํฉ๋ฒ์น์ ๋ง์กฑํ๋ ์๋๋ฅผ ์ด๋ค ์์๋ก ๋ํด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ๊ณ , ๋ฐ์ดํธ ์์๋ฅผ ๋ฐ๊ฟ ๊ณ์ฐํด๋ ๊ฒฐ๊ณผ์ ๋ฐ์ดํธ ์์๋ง ๋ฐ๋๋ค. ๊ทธ๋์ ๋ผ์ฐํฐ๊ฐ TTL ํ๋ ๊น์ ๋ ํค๋ ์ ์ฒด๋ฅผ ๋ค์ ํ์ง ์๊ณ ์ฐจ๋ถ๋ง ๋ํด์ ์ฒดํฌ์ฌ์ ๊ฐฑ์ ํ ์ ์๋ค.
๋ฐฐํฌ๋ณธ์ด ํ๋ ์ผ์ ๊ทธ๋ฆผ ํ ์ฅ์ผ๋ก ์ฎ๊ธฐ๋ฉด ์ด๋ ๋ค. ๋ถ๊ฒ ํ์ํ ์ ์ ๋ค์์ ๋ฐ๋ก ๋ค๋ฃฌ๋ค.

๐งช ์ฝ์ง ๋ง๊ณ ๋๋ ค ๋ณธ๋ค โ ๋ฐฐํฌ๋ณธ์ ๊ทธ๋๋ก ์ปดํ์ผ
๊ด์ฐฐ์ ์ฌ์ค๋ก ๋ฐ๊พธ๋ ค๋ฉด ์คํํด์ผ ํ๋ค. 03.txt ๋ ํจ์ ํ๋๋ฟ์ด๋ผ ๊ทธ๋๋ก๋ ๋ชป ๋๋ฆฌ๋, ํ ๊ธ์๋ ๊ณ ์น์ง ์๊ณ ํค๋ ํ ์ค๋ง ์น์ด ์ปดํ์ผ ๋จ์๋ก ๋ง๋ค์๋ค.
/* 03.txt (๋ฐฐํฌ๋ณธ) ์๋ฌธ ๊ทธ๋๋ก. CRLF ๋ง LF ๋ก ๋ฐ๊ฟจ๊ณ ๊ทธ ๋ฐ์ ํ ๊ธ์๋ ์๋์ง ์์๋ค. */
#include <sys/types.h> /* u_short */
u_short Malware_L03(u_short * data,u_short length)
{
register long value;
u_short i;
for(i=0;i<(length>>1);i++)
value+=data[i];
if((length&1)==1)
value+=(data[i]<<8);
value=(value&65535)+(value>>16);
return(~value);
}์ฌ๊ธฐ์ 16์ง ๋ฌธ์์ด์ ๋ฐ์ ํจ์์ ๋จน์ด๋ ๊ป๋ฐ๊ธฐ๋ฅผ ๋ถ์ธ๋ค.
/* driver.c โ ๋ฐฐํฌ๋ณธ ํจ์๋ฅผ ๊ทธ๋๋ก ํธ์ถํด ๋ณด๋ ๊ป๋ฐ๊ธฐ.
* ์ฌ์ฉ๋ฒ: ./cksum <hex๋ฌธ์์ด> (์: ./cksum 4500003ca1b64000400600000a000001)
* hex ๋ฅผ ๋ฐ์ดํธ๋ก ํ์ด Malware_L03(buf, len) ์ ๋ถ๋ฅด๊ณ ๊ฒฐ๊ณผ๋ฅผ 16์ง์๋ก ์ฐ๋๋ค. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
u_short Malware_L03(u_short * data, u_short length); /* snippet.c */
int main(int argc, char **argv)
{
static unsigned char buf[65536];
size_t n = 0;
const char *h;
if (argc != 2) { fprintf(stderr, "usage: %s <hex>\n", argv[0]); return 2; }
h = argv[1];
if (strlen(h) % 2) { fprintf(stderr, "hex ๊ธธ์ด๊ฐ ํ์๋ค\n"); return 2; }
while (*h) {
char b[3] = { h[0], h[1], 0 };
buf[n++] = (unsigned char)strtoul(b, NULL, 16);
h += 2;
}
printf("len=%zu Malware_L03=0x%04x\n", n, Malware_L03((u_short *)buf, (u_short)n));
return 0;
}gcc -O0 -g -Wall -Wextra -o cksum snippet.c driver.c; ./cksum 0001f203f4f5f6f7; ./cksum 4500003c1c46400040060000ac100a63ac100a0c
์ฒซ ์
๋ ฅ 00 01 f2 03 f4 f5 f6 f7 ์ RFC 1071 3์ฅ์ด ์์ ๋ก ์ฐ๋ ๋ฐ๋ก ๊ทธ ๋ฐ์ดํธ์ด์ด๋ค. RFC ๋ ์ฌ๊ธฐ์ 1์ ๋ณด์ ํฉ์ด ddf2 ๋ผ๊ณ ์ ์ด ๋จ๋ค. ์ฒดํฌ์ฌ์ ๊ทธ ๋ณด์๋๊น 220d ์ฌ์ผ ํ๋ค.
๊ทธ๋ฐ๋ฐ ์ฐ๋ฆฌ ํจ์๋ 0x0d22 ๋ฅผ ๋ฑ์๋ค. ๋ค์งํ ์๋ค.
โถ๐ ์ฝ์ง โ ๋ฐ์ดํธ๊ฐ ๋ค์งํ ๋์์ ํ์ฐธ ๋ถ๋ค๊ณ ์์๋ค
์ฒ์์๋ ์ด๊ฑธ ๋ถ์ผ์น๋ก ๋ดค๋ค. 0d22 ์ 220d ๋ ๋ค๋ฅธ ์๋๊น.
์ฐฉ๊ฐ์ ์ง์ ์ "๋ฐํ๊ฐ์ ํ๋ฉด์ ์ฐ์ 16์ง์"์ "๊ทธ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ์ ๋์ ๋ฐ์ดํธ ์์"๋ฅผ ๊ฐ์ ๊ฒ์ผ๋ก ๋ณธ ๋ฐ ์์๋ค.
์ด ํจ์๋ ์๋๋ฅผ ํธ์คํธ ์์๋ก ์ฝ๋๋ค. x86-64 ๋ ๋ฆฌํ์๋์ธ์ด๋ผ ๋ฉ๋ชจ๋ฆฌ์ 45 00 ์ u_short ๋ก ์ฝ์ผ๋ฉด ์์น๋ 0x0045 ๋ค. ๊ท๊ฒฉ์ด ๋งํ๋ ์๋ 0x4500 ๊ณผ ๋ฐ์ดํธ๊ฐ ๋ค์งํ ์๋ค. ๊ทธ๋ ๊ฒ ๋ค์งํ ์ฑ๋ก ๊ณ์ ๋ํ ๋ค ๊ฒฐ๊ณผ u_short ๋ฅผ ๋ค์ ๋ฉ๋ชจ๋ฆฌ์ ์ฐ๋ฉด ํ ๋ฒ ๋ ๋ค์งํ๋ค. ๋ ๋ฒ ๋ค์งํ์ผ๋ ์ ์ ์ ๋๊ฐ๋ ๋ฐ์ดํธ๋ ๊ท๊ฒฉ๋๋ก๋ค.
์ฆ ํ๋ฉด์ 0x0d22 ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ฐ๋ฉด 22 0d ๊ฐ ๋๊ณ , ๊ทธ๊ฒ ๊ณง RFC ๊ฐ ๋งํ 220d ๋ค. RFC 1071 3์ฅ์ด "Normal Order" ์ "Swapped Order" ๋ ์ด์ ๋๋ํ ๊ณ์ฐํด ๋ณด์ฌ ์ฃผ๋ ์ด์ ๊ฐ ์ ํํ ์ด๊ฒ์ด๋ค โ ์ด๋ ์ชฝ์ผ๋ก ๋ํด๋ ๋ง์ง๋ง์ ํ ๋ฒ ๋ค์ง์ผ๋ฉด ๊ฐ์ ๊ฐ์ด ๋๋ค.
๊ทธ๋์ ์ดํ ๋น๊ต๋ ์ ๋ถ ์ ์ ์์๋ก ๋ฐ๊ฟ์ ํ๋ค. reference.py ์ to_wire() ๊ฐ ๊ทธ ์ผ๋ง ํ๋ค.
RFC ๋ฌธ์๋ฅผ ์์ ๋์ ๋๊ณ ๊ฐ์ ํ๋ฉด์์ ๋์กฐํด ๋ณด๋ฉด ๋ช ํํ๋ค.
sed -n "254,269p" rfc1071.txt; ./cksum 0001f203f4f5f6f7
๋ ๋ฒ์งธ ์
๋ ฅ์ ์ฒดํฌ์ฌ ํ๋๋ฅผ 0์ผ๋ก ๋น์ด 20๋ฐ์ดํธ IP ํค๋๋ค. ๋ฐํ๊ฐ 0xe6b1 ์ ๋ฉ๋ชจ๋ฆฌ ์์๋ก ์ฐ๋ฉด b1 e6 โ ์ด ํค๋์ ์ ๋ต ์ฒดํฌ์ฌ 0xb1e6 ์ด๋ค.
๐ ์ปดํ์ผ ๊ฒฐ๊ณผ๋ฅผ ๋๊ตฌ๋ก ํ์ธ
์์ค๋ฅผ ์ฝ์ ๊ฒ๊ณผ ์ปดํ์ผ๋ฌ๊ฐ ๋ง๋ ๊ฒ์ด ๊ฐ์์ง๋ ๋ฐ๋ก ๋ด์ผ ํ๋ค. ํนํ register long value; ๊ฐ ์ค์ ๋ก ์ด๋ ๋ ์ง์คํฐ๋ก ๊ฐ๋์ง, ์บ๋ฆฌ ํด๋ฉ์ด ๋ช ๋ฒ ๋๋์ง๊ฐ ๋ค์์ ์ค์ํด์ง๋ค.
๋์ค์ด์
๋ธ๋ฆฌ์ ์ฃผ์์ ์น๋ ์นํ ๊ท์น์ ํ์ผ๋ก ๋ฐ๋ก ๋๋ค. ์ธ๋ผ์ธ์ผ๋ก sed ์คํฌ๋ฆฝํธ๋ฅผ ์ฐ๋ฉด ๋ฐ์ดํ๊ฐ ์
ธ์ ์ง๋๋ฉฐ ๊นจ์ง๋ค.
# annotate.sed โ objdump ์ถ๋ ฅ์ ์ฃผ์๋ง ์น๋๋ค(๋ช
๋ นยท์ฃผ์๋ ์๋์ง ์๋๋ค).
s/\(movzx eax,WORD PTR \[rax\]\)$/\1 <-- 16๋นํธ ์๋ ํ๋๋ฅผ ํธ์คํธ ์์๋ก ์ฝ๋๋ค/
s/\(add rbx,rax\)$/\1 <-- value ๋ rbx. ์ฌ๊ธฐ์ ๋์ฐํ๋ค/
s/\(shr ax,1\)$/\1 <-- length>>1 = ์๋ ๊ฐ์/
s/\(and eax,0x1\)$/\1 <-- length \& 1 : ํ์ ๋ฐ์ดํธ๊ฐ ๋จ์๋/
s/\(shl eax,0x8\)$/\1 <-- ๋ฌธ์ ์ data\[i\]<<8. 8๋นํธ ๋ฐ์ด ์ฌ๋ฆฐ๋ค/
s/\(movzx eax,bx\)$/\1 <-- value \& 65535/
s/\(sar rdx,0x10\)$/\1 <-- value >> 16/
s/\(lea rbx,\[rax+rdx\*1\]\)$/\1 <-- ์บ๋ฆฌ ํด๋ฉ. ๋ฑ ํ ๋ฒ๋ฟ์ด๋ค/
s/\(not eax\)$/\1 <-- ~value, ๋ฐํ์ ax 16๋นํธ๋ก ์๋ฆฐ๋ค/objdump -d --no-show-raw-insn -M intel cksum | sed -n "/<Malware_L03>:/,/ret/p" | sed -f annotate.sed
์ธ ๊ฐ์ง๊ฐ ๋ณด์ธ๋ค.
์ฒซ์งธ, value ๋ rbx ๋ค. ํจ์ ์๋จธ๋ฆฌ์์ push rbx ๋ก ํธ์ถํ ์ชฝ์ ๊ฐ์ ์ ์ฅํด ๋๋๋ฐ, ๊ทธ ๋ค๋ก rbx ๋ฅผ 0์ผ๋ก ๋๋ ๋ช
๋ น์ด ์๋ค. ๊ณง์ฅ add rbx,rax ๋ก ๋์ฐ์ด ์์๋๋ค. ์์ค์ ์ด๊ธฐํ๊ฐ ์์ผ๋ ๋น์ฐํ ๊ฒฐ๊ณผ๋ค.
๋์งธ, ํ์ ๋ฐ์ดํธ ์ฒ๋ฆฌ๋ movzx eax,WORD PTR [rax] ๋ค์ shl eax,0x8 ์ด๋ค. ์๋ ํ๋๋ฅผ ํต์งธ๋ก ์ฝ๊ณ 8๋นํธ ๋ฐ์ด ์ฌ๋ฆฐ๋ค.
์
์งธ, ์บ๋ฆฌ ํด๋ฉ์ movzx eax,bx / sar rdx,0x10 / lea rbx,[rax+rdx*1] ์ธ ๋ช
๋ น๋ฟ์ด๋ค. ์ ๋ ๋์์ด ํ ๋ฒ๋ฐ์ ์๋ค.
์ ์ ์ผ๋ก ์ฝ์ ๊ฑธ ์คํ ์ค์๋ ํ์ธํ๋ค. gdb ๋ฐฐ์น ์คํฌ๋ฆฝํธ๋ ์ด๋ ๋ค.
# cmds.gdb โ ๋ฐฐํฌ๋ณธ ํจ์๊ฐ ์คํ๋๋ ๋์ value(=rbx) ๋ฅผ ์ค์ ๋ก ๋ค์ฌ๋ค๋ณธ๋ค.
# ์ ์ ๋ถ์์์ "value ๋ rbx ์ ์กํ๊ณ ์ด๊ธฐํ๊ฐ ์๋ค"๊ณ ์ฝ์ ๊ฒ์ ๋ฐํ์์ผ๋ก ํ์ธํ๋ค.
set confirm off
set pagination off
break Malware_L03
break *(Malware_L03 + 0x73)
run 4500003c1c46400040060000ac100a63ac100a0c
printf "[1] ์ง์
์งํ rbx(=value ์ด๊ธฐ๊ฐ) = 0x%lx\n", $rbx
continue
printf "[2] ๋์ฐ ๋๋ ๋ค rbx(=value) = 0x%lx\n", $rbx
printf " value & 65535 = 0x%04lx, value >> 16 = 0x%lx\n", $rbx & 0xffff, $rbx >> 16
printf " ํด๋ฉ 1ํ ๊ฒฐ๊ณผ = 0x%lx (์ฌ๊ธฐ์ ๋ฉ์ถ๋ค)\n", ($rbx & 0xffff) + ($rbx >> 16)
x/4i $pc
finishgdb -q -batch -x cmds.gdb --args ./cksum 4500003c1c46400040060000ac100a63ac100a0c
๋์ฐ์ด ๋๋ ์์ ์ value ๊ฐ 0x1194d ๋ค. 16๋นํธ๋ฅผ ๋๊ฒผ์ผ๋ ํด๋ฉ์ด ํ์ํ๊ณ , ํ ๋ฒ ์ ์ผ๋ฉด 0x194e ๊ฐ ๋๋ค. ์ด๋ฒ์ ๊ทธ ๊ฐ์ด ๋ค์ 16๋นํธ๋ฅผ ๋์ง ์์์ ๊ฒฐ๊ณผ๊ฐ ๋ง์๋ค. ๋ฐํ๊ฐ 59057 ์ 0xe6b1 ์ด๋ค.
"์ด๋ฒ์ ์ ๋์๋ค"๋ ๋ง์ ๋ค์ง์ผ๋ฉด ๋๋ ๊ฒฝ์ฐ๊ฐ ์๋ค๋ ๋ป์ด๋ค. ๊ทธ ์๊ธฐ๋ ์กฐ๊ธ ๋ค์.
๐ ์ฒซ ๋น๋๊ฐ ๋ง์ ๊ฑด ์ด์ด์๋ค
โถ๐ ์ฝ์ง โ ๊ฒฝ๊ณ ํ๋ ์์ด ๋น๋๋๊ธธ๋ ๋ฉ์ฉกํ ์ฝ๋์ธ ์ค ์์๋ค
-Wall -Wextra ๋ฅผ ๋ถ์ฌ ๋น๋ํ๋๋ฐ ๊ฒฝ๊ณ ๊ฐ ํ ์ค๋ ์ ๋์๋ค. ๊ทธ๋์ ๋์ด๊ฐ๋ค.
์ต์ ํ๋ฅผ ์ผ ๋ณด๊ณ ์์ผ ์์๋ค.
gcc -O2 -Wall -Wextra -o cksum_O2 snippet.c driver.c
-Wmaybe-uninitialized ๋ ๋ฐ์ดํฐ ํ๋ฆ ๋ถ์์ด ํ์ํด์ -O0 ์์๋ ์์ ์ผ์ง์ง ์๋๋ค. ์ต์ ํ ์์ด ๋น๋ํ๋ฉด ์ด ์ฝ๋๋ ์กฐ์ฉํ ํต๊ณผํ๋ค.
๊ทธ๋ผ -O0 ๋น๋๋ ์ ์ ๋ต์ ๋๋. value ๊ฐ rbx ์ ์กํ๊ณ , main ์ด ๊ทธ ์์ ์ rbx ์ ๋ง์นจ 0์ ๋ค๊ณ ์์๊ธฐ ๋๋ฌธ์ด๋ค. ์ฐ์ฐ์ด๋ค.
์ฐ์ฐ์ด๋ผ๋ ๊ฑธ ๋ณด์ด๋ ค๋ฉด rbx ๋ฅผ ์ฐ๋ฆฌ๊ฐ ์ ํด์ ๋ฃ์ด ๋ณด๋ฉด ๋๋ค. ์ด์
๋ธ๋ฆฌ ๊ป๋ฐ๊ธฐ ํ๋๋ฉด ์ถฉ๋ถํ๋ค.
/* dirty_rbx.S โ ํธ์ถ ์ง์ rbx ์ ์ํ๋ ๊ฐ์ ๋ฃ๊ณ ๋ฐฐํฌ๋ณธ ํจ์๋ฅผ ๋ถ๋ฅธ๋ค.
*
* ์ rbx ๋: 03.txt ์ register long value ๋ฅผ gcc ๊ฐ rbx ์ ๋ฐฐ์ ํ๋๋ฐ,
* ์ด๊ธฐํ๊ฐ ์์ด์ "ํธ์ถํ ์ชฝ์ด rbx ์ ๋จ๊ฒจ ๋ ๊ฐ"์ด ๊ทธ๋๋ก ์ฒซ ๋์ฐ๊ฐ์ด ๋๋ค.
* ๊ทธ๊ฒ ์ฐ์ฐํ 0 ์ด๋ฉด ์ ์ ๋์์ฒ๋ผ ๋ณด์ด๊ณ , ์๋๋ฉด ์ฒดํฌ์ฌ์ด ํต์งธ๋ก ์ด๊ธ๋๋ค.
*
* long call_dirty(void *data, unsigned short len, unsigned long seed);
* rdi=data, esi=len, rdx=seed
*/
.text
.globl call_dirty
.type call_dirty, @function
call_dirty:
push %rbx
mov %rdx, %rbx /* value ๊ฐ ์์ํ ์ฐ๋ ๊ธฐ๊ฐ์ ์ฐ๋ฆฌ๊ฐ ์ ํ๋ค */
call Malware_L03@PLT /* rbx ๋ callee-saved ๋ผ PLT/ld.so ๋ ์ ๊ฑด๋๋ฆฐ๋ค */
pop %rbx
ret
.size call_dirty, .-call_dirty
.section .note.GNU-stack,"",@progbits/* uninit_demo.c โ "register long value;" ์ ์ด๊ธฐํ๊ฐ ์๋ค๋ ๊ฒ ์ค์ ๋ก ์ด๋ค ๊ฒฐ๊ณผ๋ฅผ ๋ด๋.
*
* ๊ฐ์ ์
๋ ฅ์ ์ฃผ๊ณ ํธ์ถ ์ง์ rbx ๊ฐ๋ง ๋ฐ๊ฟ ๊ฐ๋ฉฐ ๋ถ๋ฅธ๋ค.
* ๋น๋: gcc -O0 -g -o uninit_demo snippet.c dirty_rbx.S uninit_demo.c
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
long call_dirty(void *data, unsigned short len, unsigned long seed); /* dirty_rbx.S */
int main(void)
{
/* ์์์ ์ด ๊ต๊ณผ์ IP ํค๋(์ฒดํฌ์ฌ ํ๋๋ 0). ์ ๋ต์ ์ ์ ์์๋ก 0xb1e6 */
static const unsigned char hdr[20] = {
0x45,0x00,0x00,0x3c, 0x1c,0x46,0x40,0x00, 0x40,0x06,0x00,0x00,
0xac,0x10,0x0a,0x63, 0xac,0x10,0x0a,0x0c
};
unsigned long seeds[] = { 0, 1, 0x10, 0xdead, 0xffffffff, 0x7fffffffffffffffUL };
size_t i;
puts("ํธ์ถ ์ง์ rbx ๋ฐํ๊ฐ(ํธ์คํธ) ์ ์ ์์ RFC1071(0xb1e6)๊ณผ");
for (i = 0; i < sizeof(seeds) / sizeof(seeds[0]); i++) {
unsigned short r = (unsigned short)call_dirty((void *)hdr, sizeof(hdr), seeds[i]);
unsigned short wire = (unsigned short)((r << 8) | (r >> 8));
printf("0x%-16lx 0x%04x 0x%04x %s\n",
seeds[i], r, wire, wire == 0xb1e6 ? "์ผ์น" : "โ
๋ถ์ผ์น");
}
return 0;
}gcc -O0 -g -o uninit_demo snippet.c dirty_rbx.S uninit_demo.c; ./uninit_demo
rbx ๊ฐ 0์ผ ๋๋ง ๋ง๋๋ค. 0xdead ํ๋ ๋ค์ด ์์ผ๋ฉด ์ฒดํฌ์ฌ์ 0x0408 ์ด ๋๊ณ , ๊ทธ ํจํท์ ์์ ์ธก์์ ๊ทธ๋ฅ ๋ฒ๋ ค์ง๋ค.
์ค์ ์
์ฑ์ฝ๋ ์์ค์์ ์ด ์ค์ด ์๋ register long value = 0; ์ด์๋์ง๋ ์ ์ ์๋ค. ๋ฌธ์ ๋ก ๋ฐฐํฌ๋ ๋ฐ์ท๋ณธ์๋ ์ด๊ธฐํ๊ฐ ์๋ค๋ ๊ฒ๋ง์ด ํ์คํ๋ค.
๐ฃ ๊ฒฐํจ ์ โ ๊ท๊ฒฉ๊ณผ ๋ค๋ฅธ ์๋ฆฌ
๋ฐฐํฌ๋ณธ์ด ์ธํฐ๋ท ์ฒดํฌ์ฌ์ ์๋ํ๋ค๋ ๊ฑด ์ด์ ๋ถ๋ช ํ๋ค. ๊ทธ๋ผ ๊ท๊ฒฉ๋๋ก ํ๊ณ ์๋. ์ด๊ฑธ ์ฌ๋ ค๋ฉด ๋น๊ต ๋์์ด ์์ด์ผ ํ๋ RFC 1071 ์ ๊ทธ๋๋ก ์ฎ๊ธด ์ ๋ต์ง๋ฅผ ๋ฐ๋ก ๋ง๋ค์๋ค.
#!/usr/bin/env python3
"""reference.py โ RFC 1071 ์ธํฐ๋ท ์ฒดํฌ์ฌ์ ๊ท๊ฒฉ ๊ทธ๋๋ก ๋
๋ฆฝ ๊ตฌํํ ๊ฒ.
๋ฐฐํฌ๋ณธ ํจ์(03.txt)์ ๋น๊ตํ๊ธฐ ์ํ '์ ๋ต์ง' ์ญํ ๋ง ํ๋ค.
RFC 1071 ยง1:
(1) ๋ฐ์ดํฐ๋ฅผ 16๋นํธ ๋น
์๋์ธ ์๋๋ก ๋์ด 1์ ๋ณด์ ํฉ์ ๊ตฌํ๋ค(์บ๋ฆฌ๋ ๋๋๋ ค ๋ํ๋ค).
(2) ๊ธธ์ด๊ฐ ํ์๋ฉด ๋ง์ง๋ง ๋ฐ์ดํธ ์ค๋ฅธ์ชฝ์ 0์ผ๋ก ์ฑ์ 16๋นํธ ์๋๋ก ๋ง๋ ๋ค.
(3) ํฉ์ 1์ ๋ณด์๊ฐ ์ฒดํฌ์ฌ์ด๋ค.
๋ฐํ๊ฐ์ '์ ์ ์์ ๊ทธ๋๋ก ์ค๋ฆฌ๋' ๋น
์๋์ธ 16๋นํธ ์ ์๋ค.
"""
def rfc1071(data: bytes) -> int:
if len(data) & 1:
data = data + b"\x00" # (2) ์ค๋ฅธ์ชฝ 0 ํจ๋ฉ
total = 0
for off in range(0, len(data), 2):
total += (data[off] << 8) | data[off + 1] # (1) ๋น
์๋์ธ ์๋
total = (total & 0xFFFF) + (total >> 16) # ์บ๋ฆฌ ๋๋๋ฆฌ๊ธฐ
while total >> 16:
total = (total & 0xFFFF) + (total >> 16)
return (~total) & 0xFFFF # (3)
def snippet_model(data: bytes) -> int:
"""03.txt ๋ฅผ ๋ฆฌํ์๋์ธ ๊ธฐ๊ณ์์ ๋๋ ธ์ ๋๋ฅผ ํ์ด์ฌ์ผ๋ก ์ฎ๊ธด ๊ฒ.
- ์๋๋ ํธ์คํธ(LE) ์์๋ก ์ฝ๋๋ค
- ํ์ ๋ฐ์ดํธ ์ฒ๋ฆฌ๋ data[i]<<8 ๊ทธ๋๋ก (๋ฒํผ ๋ฐ 1๋ฐ์ดํธ๋ฅผ ๊ฐ์ด ์ฝ๋๋ค)
- ์บ๋ฆฌ ํด๋ฉ์ ์๋ฌธ๋๋ก '๋จ ํ ๋ฒ'
- ๋ฐํ์ u_short ์ ๋จ
์ด ํจ์๊ฐ ๋ฑ๋ ๊ฐ์ ํธ์คํธ ์์๋ค. ์ ์ ์ ๊ฐ๊ณผ ๋น๊ตํ๋ ค๋ฉด ๋ฐ์ดํธ๋ฅผ ๋ค์ง์ด์ผ ํ๋ค.
"""
n = len(data)
buf = data + b"\x00" # OOB 1๋ฐ์ดํธ๋ฅผ 0์ผ๋ก ๊ฐ์ (์ ์ ๋ฒํผ์ ํํ ๊ฒฝ์ฐ)
value = 0 # ์๋ฌธ์ ์ด๊ธฐํ๊ฐ ์๋ค. ์ฌ๊ธฐ์๋ 0 ์ผ๋ก ๋๋ค
i = 0
while i < (n >> 1):
value += buf[2 * i] | (buf[2 * i + 1] << 8) # LE u_short
i += 1
if n & 1:
value += (buf[2 * i] | (buf[2 * i + 1] << 8)) << 8
value = (value & 65535) + (value >> 16) # ํด๋ฉ 1ํ๋ฟ
return (~value) & 0xFFFF # u_short ์ ๋จ
def to_wire(host_u16: int) -> int:
"""LE ๊ธฐ๊ณ์์ u_short ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ๊ทธ๋๋ก ์ฐ๋ฉด ์ ์ ์์์๋ ๋ฐ์ดํธ๊ฐ ๋ค์งํ ๋ณด์ธ๋ค."""
return ((host_u16 & 0xFF) << 8) | (host_u16 >> 8)
if __name__ == "__main__":
import sys
raw = bytes.fromhex(sys.argv[1])
print(f"len={len(raw)} rfc1071(wire)=0x{rfc1071(raw):04x} "
f"snippet(host)=0x{snippet_model(raw):04x} "
f"snippet(wire)=0x{to_wire(snippet_model(raw)):04x}")ํ์ ๊ธธ์ด โ ๋ฉ์์ง ๋ฐ 1๋ฐ์ดํธ๋ฅผ ๊ฐ์ด ๋ํ๋ค
data ๋ u_short* ๋ค. ๋ฃจํ๊ฐ ๋๋ ์์ ์ i ๋ length>>1 ์ด๊ณ , data[i] ๋ ์คํ์
2i ์ 2i+1 ๋ ๋ฐ์ดํธ๋ฅผ ๊ฐ์ ธ์จ๋ค. ๊ธธ์ด๊ฐ ํ์๋ฉด 2i ๊ฐ ๋ง์ง๋ง ์ ํจ ๋ฐ์ดํธ์ด๋ฏ๋ก 2i+1 ์ ๋ฉ์์ง ๋ฐ์ด๋ค.
7๋ฐ์ดํธ ๋ฉ์์ง๋ฅผ 8๋ฐ์ดํธ ๋ฒํผ์ ๋ด๊ณ 8๋ฒ์งธ ๋ฐ์ดํธ๋ง ๋ฐ๊ฟ ๋ณด๋ฉด ๋ฐ๋ก ๋๋ฌ๋๋ค.
/* oob_demo.c โ ๊ธธ์ด๊ฐ ํ์์ผ ๋ data[i] ๊ฐ ์ ๋ง ๋ฒํผ ๋ฐ์ ์ฝ๋์ง ํ์ธํ๋ค.
*
* ๋ฉ์์ง๋ 7๋ฐ์ดํธ๋ฟ์ธ๋ฐ data ๋ u_short* ๋ผ data[3] ์ 8๋ฒ์งธ ๋ฐ์ดํธ๊น์ง ๋์ด์จ๋ค.
* ๊ทธ 8๋ฒ์งธ ๋ฐ์ดํธ๋ง ๋ฐ๊ฟ ๊ฐ๋ฉฐ ๊ฐ์ 7๋ฐ์ดํธ ๋ฉ์์ง์ ์ฒดํฌ์ฌ์ด ํ๋ค๋ฆฌ๋์ง ๋ณธ๋ค.
*
* ๋น๋: gcc -O0 -g -o oob_demo snippet.c oob_demo.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
u_short Malware_L03(u_short *data, u_short length); /* snippet.c */
int main(void)
{
static const unsigned char msg[7] = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07 };
unsigned char guards[] = { 0x00, 0x41, 0xff };
size_t g;
printf("๋ฉ์์ง 7๋ฐ์ดํธ: 01 02 03 04 05 06 07 (๊ธธ์ด ์ธ์ length=7 ๋ก ๊ณ ์ )\n\n");
printf("๋ฒํผ ๋ฐ 8๋ฒ์งธ ๋ฐ์ดํธ ๋ฐํ๊ฐ(ํธ์คํธ)\n");
for (g = 0; g < sizeof(guards); g++) {
unsigned char *p = malloc(8);
memcpy(p, msg, 7);
p[7] = guards[g]; /* ๋ฉ์์ง๊ฐ ์๋ ์๋ฆฌ */
printf("0x%02x 0x%04x\n", guards[g], Malware_L03((u_short *)p, 7));
free(p);
}
printf("\n๊ฐ์ ๋ฉ์์ง์ธ๋ฐ ๊ฐ์ด ๋ฌ๋ผ์ง๋ฉด, ํจ์๊ฐ ๋ฉ์์ง ๋ฐ 1๋ฐ์ดํธ๋ฅผ ๊ฐ์ด ๋ํ ๊ฒ์ด๋ค.\n");
return 0;
}gcc -O0 -g -Wall -o oob_demo snippet.c oob_demo.c; ./oob_demo
๋ฉ์์ง๋ ๊ทธ๋๋ก์ธ๋ฐ ๊ฒฐ๊ณผ๊ฐ ์ ๋ค ๋ค๋ฅด๋ค. ํจ์๊ฐ ๋ฉ์์ง๊ฐ ์๋ ๋ฐ์ดํธ๋ฅผ ๊ณ์ฐ์ ๋ฃ์๋ค๋ ๋ป์ด๋ค.
์ํํธ ๋ฐฉํฅ๋ ์ด๊ธ๋ ์๋ค. ๊ท๊ฒฉ์ ๋ง์ง๋ง ํ์ ๋ฐ์ดํธ์ ์ค๋ฅธ์ชฝ์ 0์ผ๋ก ์ฑ์ฐ๋ผ๊ณ ํ๋ค. BSD ๊ณ์ด in_cksum ์ ์ด๊ฑธ *(u_char *)(&answer) = *(u_char *)w; ๋ก ์ฒ๋ฆฌํ๋๋ฐ, 16๋นํธ ๋ณ์์ ์ฒซ ๋ฐ์ดํธ์ ๊ทธ๋๋ก ์จ ๋ฃ๋ ๋ฐฉ์์ด๋ผ ๋ฆฌํ์๋์ธ์์๋ ํ์ ๋ฐ์ดํธ, ๋น
์๋์ธ์์๋ ์์ ๋ฐ์ดํธ๊ฐ ๋๋ค. ์ด๋ ์ชฝ์ด๋ ๊ท๊ฒฉ๊ณผ ๋ง๋๋ค. ์ฌ๊ธฐ์๋ ์๋๋ฅผ ํต์งธ๋ก ์ฝ์ด 8๋นํธ ๋ฐ์ด ์ฌ๋ฆฌ๋ฏ๋ก ๋ ๋ค ์๋๋ค.
๋ํ ๋ฒํผ โ ์บ๋ฆฌ ํด๋ฉ์ด ํ ๋ฒ๋ฟ์ด๋ค
(value&65535)+(value>>16) ์ ๊ฒฐ๊ณผ๊ฐ ๋ค์ 16๋นํธ๋ฅผ ๋์ ์ ์๋ค. value = 65536q + r ๋ก ๋๋ฉด ์ด ์์ q + r ์ธ๋ฐ, r ์ด ํฌ๊ณ q ๊ฐ 1 ์ด์์ด๋ฉด ํฉ์ด 65536์ ๋๊ธด๋ค. ํ์ค ๊ตฌํ์ด sum += (sum >> 16); ์ ํ ์ค ๋ ๋๋ ์ด์ ๋ค.
๋ ๊ฒฐํจ์ ํ ๋ฒ์ ์ฌ๋ ค๊ณ ๋ฌด์์ ์ ๋ ฅ์ผ๋ก ์ ๋ต์ง์ ๋ง๋ ๋ดค๋ค.
#!/usr/bin/env python3
"""difftest.py โ ๋ฐฐํฌ๋ณธ ํจ์(์ปดํ์ผํ ./cksum)์ RFC 1071 ์ ๋ต์ง๋ฅผ ๋ฌด์์ ์
๋ ฅ์ผ๋ก ๋ง๋ ๋ณธ๋ค.
'์ด ํจ์๊ฐ ์ธํฐ๋ท ์ฒดํฌ์ฌ์ด๋ค'๋ฅผ ๋์ด ์๋๋ผ ์ค์ธก์ผ๋ก ํ์ ํ๋ ๊ฒ ๋ชฉ์ ์ด๋ค.
๊ธธ์ด๋(์ง์ ์ํ / ํ์ / ์ง์ ๋ํ)๋ง๋ค ์ผ์น ๊ฐ์๋ฅผ ์ธ๊ณ , ์ด๊ธ๋ ๊ฒ์ ์ฐจ์ด๊ฐ ๋ถํฌ๋ก ์์ฝํ๋ค.
"""
import collections
import random
import subprocess
from reference import rfc1071, to_wire
random.seed(20261208) # ์ฌํ ๊ฐ๋ฅํ๊ฒ ๊ณ ์ (๋ฌธ์ ๊ณต๊ฐ์ผ)
BIN = "./cksum"
def run_c(raw: bytes) -> int:
"""์ปดํ์ผํ ๋ฐฐํฌ๋ณธ ํจ์๋ฅผ ์ค์ ๋ก ์คํํด ํธ์คํธ ์์ u_short ๋ฅผ ๋ฐ์์จ๋ค."""
out = subprocess.run([BIN, raw.hex()], capture_output=True, text=True, check=True).stdout
return int(out.split("=")[-1], 16)
def sweep(lengths, label):
ok = 0
deltas = collections.Counter()
sample = None
for n in lengths:
raw = bytes(random.randrange(256) for _ in range(n))
got, want = to_wire(run_c(raw)), rfc1071(raw)
if got == want:
ok += 1
else:
deltas[want - got] += 1
if sample is None:
sample = (raw, got, want)
bad = sum(deltas.values())
print(f"[{label:<22}] ํ๋ณธ {ok + bad:>3} ์ผ์น {ok:>3} ๋ถ์ผ์น {bad:>3}")
if bad:
top = ", ".join(f"{d:+d}: {c}ํ" for d, c in deltas.most_common(4))
print(f" ์ฐจ์ด(RFC1071 - ๋ฐฐํฌ๋ณธ) ๋ถํฌ: {top}")
raw, got, want = sample
print(f" ์ฒซ ์ฌ๋ก len={len(raw)} data={raw[:12].hex()}... "
f"๋ฐฐํฌ๋ณธ=0x{got:04x} RFC1071=0x{want:04x}")
return ok, bad
print("=== ๋ฐฐํฌ๋ณธ ํจ์ vs RFC 1071 ์ ๋ต์ง (์
๋ ฅ์ ์๋ ๊ณ ์ ๋์) ===")
sweep([random.randrange(1, 400) * 2 for _ in range(300)], "์ง์ 2~798B")
sweep([random.randrange(0, 400) * 2 + 1 for _ in range(300)], "ํ์ 1~799B")
sweep([random.randrange(20000, 60000) & ~1 for _ in range(120)], "์ง์ 20K~60KB")python3 difftest.py
์ฝ๋ ๋ฒ์ด ์ ์ผ๋ก ๊ฐ๋ฆฐ๋ค.
์ง์ ๊ธธ์ด ์ํ์ 300๊ฐ ์ ๋ถ ์ผ์น. ์ฌ๊ธฐ๊ฐ ๊ฒฐ๋ก ์ ๋ผ๋๋ค. ๊ท๊ฒฉ ๊ตฌํ๊ณผ ํ ๋นํธ๋ ๋ค๋ฅด์ง ์๋ค.
ํ์ ๊ธธ์ด๋ 299๊ฐ ๋ถ์ผ์น. ์ฐจ์ด๊ฐ ์ ๊ฐ๊ฐ์ธ ๊ฒ๋ ์์ ๋ฒํผ ๋ฐ ์ฝ๊ธฐ์ ๋ง์๋จ์ด์ง๋ค โ ๋ธ๋ ค ๋ค์ด์จ ๋ฐ์ดํธ๊ฐ ๋งค๋ฒ ๋ค๋ฅด๋๊น.
๋ํ ์ง์ ๊ธธ์ด๋ 10๊ฐ ๋ถ์ผ์น์ธ๋ฐ ์ฐจ์ด๊ฐ ์ ๋ถ ์ ํํ -256. ์ ์ ์์์์ 256 ์ฐจ์ด๋ ํธ์คํธ ์์์์ 1 ์ฐจ์ด๋ค. ์ ๋ค ๋ง ์บ๋ฆฌ ํ๋๊ฐ ๊ทธ๋๋ก ๋จ์ ๊ฒ์ด๋ค.
์ด ์บ๋ฆฌ ๊ฒฐํจ์ด ์ผ๋ง๋ ์งง์ ์ ๋ ฅ์์๋ ํฐ์ง๋์ง ๋ฐ๋ก ์ฌ ๋ดค๋ค.
#!/usr/bin/env python3
"""minimal_carry.py โ '์บ๋ฆฌ ํด๋ฉ 1ํ' ๊ฒฐํจ์ ํฐ๋จ๋ฆฌ๋ ๊ฐ์ฅ ์งง์ ์
๋ ฅ์ ์ฐพ๋๋ค.
value = 65536*q + r ๋ก ๋๋ฉด (value&65535)+(value>>16) = q+r ์ด๋ค.
์ด ๊ฐ์ด ๋ค์ 65536 ์ ๋์ผ๋ฉด ํด๋ฉ์ด ํ ๋ฒ ๋ ํ์ํ๋ฐ ๋ฐฐํฌ๋ณธ์ ๊ฑฐ๊ธฐ์ ๋ฉ์ถ๋ค.
q+r >= 65536 ์ด ๋๋ ค๋ฉด ์๋ ์ k >= q+2 ์ฌ์ผ ํ๋ฏ๋ก ์ต์ k=3, ์ฆ 6๋ฐ์ดํธ๋ค.
"""
import itertools
import subprocess
from reference import rfc1071, to_wire
def run_c(raw: bytes) -> int:
out = subprocess.run(["./cksum", raw.hex()], capture_output=True, text=True, check=True).stdout
return int(out.split("=")[-1], 16)
def le(w): # ํธ์คํธ(LE) u_short ๋ฅผ ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํธ๋ก
return bytes([w & 0xFF, w >> 8])
print("์๋ ์ k ๋ฅผ 2๋ถํฐ ์ฌ๋ฆฌ๋ฉฐ ๋ฐ๋ก๊ฐ ๋์ค๋ ์ฒซ ์ง์ ์ ์ฐพ๋๋ค")
for k in range(2, 6):
hit = None
# ๊ฐ ์๋๋ฅผ 0xffff ๋ก ์ฑ์ฐ๊ณ ๋ง์ง๋ง ํ๋๋ง ํ๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํ๋ค
for last in range(0, 0x10000):
raw = le(0xFFFF) * (k - 1) + le(last)
value = 0xFFFF * (k - 1) + last
if ((value & 65535) + (value >> 16)) >> 16:
hit = (raw, last)
break
if hit is None:
print(f" k={k} ({k*2}B): ๋ฐ๋ก ์์")
continue
raw, last = hit
got, want = to_wire(run_c(raw)), rfc1071(raw)
print(f" k={k} ({k*2}B): ๋ฐ๋ก ๋ฐ๊ฒฌ data={raw.hex()} (๋ง์ง๋ง ์๋ 0x{last:04x})")
print(f" ๋ฐฐํฌ๋ณธ(์ ์ ์์)=0x{got:04x} RFC1071=0x{want:04x} โ {'๋ค๋ฆ' if got != want else '๊ฐ์'}")
breakpython3 minimal_carry.py
6๋ฐ์ดํธ๋ค. ๋์ฉ๋ ํ์ด๋ก๋์์๋ง ๋์ค๋ ํฌ๊ทํ ๋ฌธ์ ๊ฐ ์๋๋ผ, ์๋ ์ธ ๊ฐ์ง๋ฆฌ ์ ๋ ฅ์์ ์ด๋ฏธ ๊ฐ๋ฆฐ๋ค.
๐ฏ ๊ฒฐ์ ์ ์ฆ๊ฑฐ โ ์ง์ง ํจํท๊ณผ ๋ง์ถฐ ๋ณธ๋ค
์ฌ๊ธฐ๊น์ง๋ ์ ๋ถ ๋ด๊ฐ ๋ง๋ ์ ๋ ฅ์ด๋ค. ๋ง์ง๋ง ํ์ธ์ ์ปค๋์ด ์ง์ ๊ณ์ฐํด ์ ์ ์ ์ฌ๋ฆฐ ๊ฐ๊ณผ ๋ง๋๋ ๊ฒ์ผ๋ก ํ๋ค.
๋ฃจํ๋ฐฑ์ผ๋ก ping ์ ์ธ ๋ฒ ์๊ณ tcpdump ๋ก ์ก๋๋ค.
#!/usr/bin/env bash
# capture_live.sh โ ์ง์ง ํจํท์ ํ๋ ์ก์ ์จ๋ค.
# ๋ฃจํ๋ฐฑ์ผ๋ก ping ์ 3๋ฒ ์๊ณ tcpdump ๋ก pcap ์ ๋จ๊ธด๋ค. ๋ง๋ค์ด๋ธ ๋ฐ์ดํฐ๊ฐ ์๋๋ผ
# ์ปค๋์ด ์ง์ ์ฒดํฌ์ฌ์ ์ฑ์ ์ ์ ์ ์ฌ๋ฆฐ ๋ฐ์ดํธ์ฌ์ผ ๋น๊ต์ ์๋ฏธ๊ฐ ์๋ค.
set -euo pipefail
cd "$(dirname "$0")"
OUT=${1:-live_icmp.pcap}
sudo -n tcpdump -i lo -c 6 -s 0 -w "$OUT" icmp >/dev/null 2>&1 &
TD=$!
sleep 1
ping -c 3 -i 0.3 -s 32 127.0.0.1 >/dev/null
wait $TD || true
sudo -n chown "$(id -un)":"$(id -gn)" "$OUT"
ls -l "$OUT"
tcpdump -r "$OUT" -n -c 6 2>/dev/nullrm -f live_icmp.pcap && ./capture_live.sh
ping ์ด ๋ง๋ ๊ฒ๋, ์ปค๋์ด ๋๋๋ ค ์ค ๊ฒ๋ ์ฐ๋ฆฌ ์์ ๊ฑฐ์น์ง ์์ ๊ฐ์ด๋ค. ์ด์ ์ด pcap ์ ํ์ฑํด IP ํค๋์ ICMP ๋ฉ์์ง์ ์ฒดํฌ์ฌ ์๋ฆฌ๋ฅผ 0์ผ๋ก ๋๋๋ฆฐ ๋ค, ์ปดํ์ผํ ๋ฐฐํฌ๋ณธ ํจ์์ ๊ทธ๋๋ก ๋จน์ธ๋ค.
#!/usr/bin/env python3
"""verify_live.py โ ์ค์ ๋ก ์ ์ ์ ์ง๋๊ฐ ํจํท์ ์ฒดํฌ์ฌ์ ๋ฐฐํฌ๋ณธ ํจ์๋ก ๋ค์ ๊ณ์ฐํด ๋ณธ๋ค.
capture_live.sh ๊ฐ tcpdump ๋ก ๋จ๊ธด pcap ์ ์ฝ์ด
ยท IP ํค๋ ์ฒดํฌ์ฌ
ยท ICMP ๋ฉ์์ง ์ฒดํฌ์ฌ
๋ ์๋ฆฌ๋ฅผ 0 ์ผ๋ก ๋๋๋ฆฐ ๋ค ์ปดํ์ผํ ๋ฐฐํฌ๋ณธ ํจ์(./cksum)์ ๊ทธ๋๋ก ๋จน์ธ๋ค.
์ปค๋์ด ์ค์ ๋ก ์จ ๋ฃ์ ๊ฐ๊ณผ ํ ๋นํธ๋ผ๋ ๋ค๋ฅด๋ฉด '์ธํฐ๋ท ์ฒดํฌ์ฌ์ด๋ค'๋ผ๋ ๊ฒฐ๋ก ์ด ๋ฌด๋์ง๋ค.
"""
import struct
import subprocess
import sys
from reference import to_wire
PCAP = sys.argv[1] if len(sys.argv) > 1 else "live_icmp.pcap"
def run_c(raw: bytes) -> int:
out = subprocess.run(["./cksum", raw.hex()], capture_output=True, text=True, check=True).stdout
return int(out.split("=")[-1], 16)
def packets(path):
blob = open(path, "rb").read()
magic = blob[:4]
endian = "<" if magic in (b"\xd4\xc3\xb2\xa1", b"\x4d\x3c\xb2\xa1") else ">"
linktype = struct.unpack(endian + "I", blob[20:24])[0]
off = 24
while off + 16 <= len(blob):
_, _, caplen, _ = struct.unpack(endian + "IIII", blob[off:off + 16])
yield linktype, blob[off + 16: off + 16 + caplen]
off += 16 + caplen
L2LEN = {0: 4, 1: 14, 113: 16, 101: 0} # NULL / EN10MB / LINUX_SLL / RAW
print(f"pcap: {PCAP}")
rows = 0
for linktype, frame in packets(PCAP):
ip = frame[L2LEN.get(linktype, 14):]
if not ip or ip[0] >> 4 != 4:
continue
ihl = (ip[0] & 0xF) * 4
hdr, payload = ip[:ihl], ip[ihl:]
proto = hdr[9]
# --- IP ํค๋ ---
on_wire_ip = struct.unpack("!H", hdr[10:12])[0]
zeroed_ip = hdr[:10] + b"\x00\x00" + hdr[12:]
calc_ip = to_wire(run_c(zeroed_ip))
# --- ICMP ๋ฉ์์ง (์์ฌํค๋ ์์) ---
on_wire_l4 = calc_l4 = None
if proto == 1 and len(payload) >= 4:
on_wire_l4 = struct.unpack("!H", payload[2:4])[0]
zeroed_l4 = payload[:2] + b"\x00\x00" + payload[4:]
calc_l4 = to_wire(run_c(zeroed_l4))
kind = {8: "echo request", 0: "echo reply"}.get(payload[0] if payload else -1, "?")
okip = "์ผ์น" if calc_ip == on_wire_ip else "โ
๋ถ์ผ์น"
print(f" [{kind:<13}] IPํค๋ {ihl}B ์ ์ =0x{on_wire_ip:04x} ๋ฐฐํฌ๋ณธ=0x{calc_ip:04x} {okip}")
if calc_l4 is not None:
okl4 = "์ผ์น" if calc_l4 == on_wire_l4 else "โ
๋ถ์ผ์น"
print(f" {'':<16} ICMP {len(payload)}B ์ ์ =0x{on_wire_l4:04x} ๋ฐฐํฌ๋ณธ=0x{calc_l4:04x} {okl4}")
rows += 1
print(f"๊ฒ์ฌํ ํจํท {rows}๊ฐ")python3 verify_live.py
12๊ณณ ์ ๋ถ ์ผ์น. ํค๋ 20๋ฐ์ดํธ๋ ์ง์, ICMP ๋ฉ์์ง 40๋ฐ์ดํธ๋ ์ง์๋ผ ์์์ ๋ณธ ๊ฒฐํจ์ด ๋ฐํํ์ง ์๋ ๊ตฌ๊ฐ์ด๋ค. ์ด ํจ์๋ IP ํค๋ ์ฒดํฌ์ฌ์ด๊ณ ICMP ์ฒดํฌ์ฌ์ด๋ฉฐ, ๊ฐ์ ๊ณ์ฐ์ด TCPยทUDP ์๋ ๊ทธ๋๋ก ์ฐ์ธ๋ค.
๐ ์๋ ์์ด์ผ ํ ์๋ฆฌ์ ๊ฝ์ ๋ณธ๋ค
๊ทธ๋ผ ์
์ฑ์ฝ๋๋ ์ด ํจ์๋ฅผ ์ ๋ค๊ณ ๋ค๋๋. ๋ณดํต ์์ผ์ผ๋ก ๋ณด๋ด๋ฉด ์ปค๋์ด ์ฒดํฌ์ฌ์ ์์์ ์ฑ์ ์ค๋ค. ๊ทธ๋ฐ๋ฐ IP_HDRINCL ์ต์
์ ์ผ ๋ก์ฐ์์ผ์ผ๋ก IP ํค๋๋ฅผ ์ง์ ์จ์ ๋ณด๋ด๋ฉด ์ปค๋์ ์๋์ง ์๋๋ค. ์ถ๋ฐ์ง ์ฃผ์๋ฅผ ์์กฐํ๋ ค๋ฉด ์ด ๊ฒฝ๋ก๋ฅผ ์จ์ผ ํ๊ณ , ๊ทธ ์๊ฐ๋ถํฐ IP ์ฒดํฌ์ฌ๋ TCP ์ฒดํฌ์ฌ๋ ์ง์ ๊ณ์ฐํด์ผ ํ๋ค.
๋ฐฐํฌ๋ณธ ํจ์๋ฅผ ๊ทธ ์๋ฆฌ์ ๊ทธ๋๋ก ๋ฃ์ด SYN ํ๋๋ฅผ ๋ง๋ค์ด ๋ดค๋ค. ์ถ๋ฐ์ง๋ 127.0.0.2 ๋ก ์์กฐํ๊ณ ๋ชฉ์ ์ง๋ 127.0.0.1 ์ด๋ผ ํจํท์ ๋ฃจํ๋ฐฑ ๋ฐ์ผ๋ก ๋๊ฐ์ง ์๋๋ค.
/* craft_send.c โ ๋ฐฐํฌ๋ณธ ํจ์๋ฅผ '์๋ ์๋ฆฌ'์ ๊ทธ๋๋ก ๊ฝ์ ๋ณธ๋ค.
*
* IP_HDRINCL ๋ก IP ํค๋๋ฅผ ์ง์ ์ฐ๋ ๋ก์ฐ์์ผ์์๋ ์ปค๋์ด IPยทTCP ์ฒดํฌ์ฌ์
* ์ฑ์ ์ฃผ์ง ์๋๋ค. ์ถ๋ฐ์ง ์ฃผ์๋ฅผ ์์กฐํ๋ ํ๋ฌ๋๊ฐ 03.txt ๊ฐ์ ํจ์๋ฅผ
* ๋ฐ๋์ ๋ค๊ณ ๋ค๋๋ ์ด์ ๊ฐ ์ด๊ฒ์ด๋ค. ์ฌ๊ธฐ์๋ SYN ํ ๊ฐ๋ง ๋ง๋ค์ด
* 127.0.0.2 -> 127.0.0.1:9 ๋ก ๋ฃจํ๋ฐฑ์๋ง ํ๋ฆฐ๋ค(์ธ๋ถ๋ก ๋๊ฐ์ง ์๋๋ค).
*
* ๋น๋: gcc -O0 -g -o craft_send snippet.c craft_send.c
* ์คํ: sudo ./craft_send (๋ก์ฐ์์ผ์ด๋ผ root ํ์)
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
u_short Malware_L03(u_short *data, u_short length); /* snippet.c โ ๋ฐฐํฌ๋ณธ ๊ทธ๋๋ก */
/* TCP ์ฒดํฌ์ฌ์ IP ํค๋์์ ๋น๋ ค ์จ ์์ฌํค๋(12B)๊น์ง ํฌํจํด ๊ณ์ฐํ๋ค (RFC 793) */
struct pseudo {
u_int32_t src, dst;
u_int8_t zero, proto;
u_int16_t len;
};
int main(void)
{
unsigned char pkt[sizeof(struct iphdr) + sizeof(struct tcphdr)];
unsigned char pbuf[sizeof(struct pseudo) + sizeof(struct tcphdr)];
struct iphdr *ip = (struct iphdr *)pkt;
struct tcphdr *tcp = (struct tcphdr *)(pkt + sizeof(struct iphdr));
struct pseudo ph;
struct sockaddr_in to;
int s, on = 1;
memset(pkt, 0, sizeof(pkt));
ip->version = 4; ip->ihl = 5; ip->tos = 0;
ip->tot_len = htons(sizeof(pkt));
ip->id = htons(0xC0DE);
ip->frag_off = 0; ip->ttl = 64; ip->protocol = IPPROTO_TCP;
ip->saddr = inet_addr("127.0.0.2"); /* ์์กฐํ ์ถ๋ฐ์ง */
ip->daddr = inet_addr("127.0.0.1");
ip->check = 0;
ip->check = Malware_L03((u_short *)ip, sizeof(struct iphdr)); /* โ ๋ฐฐํฌ๋ณธ ํจ์ */
tcp->source = htons(31337);
tcp->dest = htons(9); /* discard ํฌํธ */
tcp->seq = htonl(0x1337BEEF);
tcp->doff = 5;
tcp->syn = 1;
tcp->window = htons(1024);
tcp->check = 0;
ph.src = ip->saddr; ph.dst = ip->daddr;
ph.zero = 0; ph.proto = IPPROTO_TCP; ph.len = htons(sizeof(struct tcphdr));
memcpy(pbuf, &ph, sizeof(ph));
memcpy(pbuf + sizeof(ph), tcp, sizeof(struct tcphdr));
tcp->check = Malware_L03((u_short *)pbuf, sizeof(pbuf)); /* โ ๋ฐฐํฌ๋ณธ ํจ์ */
printf("IP ์ฒดํฌ์ฌ(๋ฐฐํฌ๋ณธ ๊ณ์ฐ) = 0x%04x\n", ntohs(ip->check));
printf("TCP ์ฒดํฌ์ฌ(๋ฐฐํฌ๋ณธ ๊ณ์ฐ) = 0x%04x\n", ntohs(tcp->check));
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("socket"); return 1; }
if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) { perror("HDRINCL"); return 1; }
to.sin_family = AF_INET; to.sin_port = 0; to.sin_addr.s_addr = ip->daddr;
if (sendto(s, pkt, sizeof(pkt), 0, (struct sockaddr *)&to, sizeof(to)) < 0) {
perror("sendto"); return 1;
}
puts("SYN 1๊ฐ ์ ์ก ์๋ฃ (127.0.0.2 -> 127.0.0.1:9, ๋ฃจํ๋ฐฑ ํ์ )");
close(s);
return 0;
}๋ณด๋ธ ๋ค tcpdump ๊ฐ ๋ญ๋ผ๊ณ ํ๋์ง ๋ด์ผ ํ๋ ๋์ ๋ฌถ์ ์คํฌ๋ฆฝํธ๋ฅผ ํ๋ ๋๋ค.
#!/usr/bin/env bash
# craft_demo.sh โ ๋ฐฐํฌ๋ณธ ํจ์๋ก ์ฑ์ด ์ฒดํฌ์ฌ์ ์ปค๋/tcpdump ๊ฐ ์ธ์ ํ๋์ง ๋ณธ๋ค.
# tcpdump -vv ๋ ์ฒดํฌ์ฌ์ ์ค์ค๋ก ์ฌ๊ณ์ฐํด (correct)/(incorrect) ๋ฅผ ๋ถ์ฌ ์ค๋ค.
set -uo pipefail
cd "$(dirname "$0")"
sudo -n tcpdump -i lo -c 1 -nvv 'tcp port 9' >craft_dump.txt 2>/dev/null &
TD=$!
sleep 1
sudo -n ./craft_send
wait $TD
echo "--- tcpdump ๊ฐ ๋ณธ ํจํท ---"
cat craft_dump.txtgcc -O0 -g -Wall -o craft_send snippet.c craft_send.c; ./craft_demo.sh
cksum 0x6146 (correct) โ tcpdump ๊ฐ ์ค์ค๋ก ๋ค์ ๊ณ์ฐํด์ ๋ง๋ค๊ณ ๋ถ์ธ ํ์๋ค. ๋ฐฐํฌ๋ณธ ํจ์๊ฐ ๊ณ์ฐํ ๊ฐ์ด ํ๋กํ ์ฝ ๊ท๊ฒฉ์ ๋ง๋๋ค๋ ๊ฒ์ ์ 3์ ๋๊ตฌ๊ฐ ํ์ธํด ์ค ์
์ด๋ค.
TCP ์ฒดํฌ์ฌ์ ํค๋๋ง์ผ๋ก ๊ณ์ฐํ์ง ์๋๋ค. ์ถ๋ฐ์งยท๋ชฉ์ ์ง ์ฃผ์์ ํ๋กํ ์ฝ ๋ฒํธ, ์ธ๊ทธ๋จผํธ ๊ธธ์ด๋ฅผ ๋ด์ 12๋ฐ์ดํธ ์์ฌํค๋๋ฅผ ์์ ๋ถ์ฌ์ ๊ฐ์ ํจ์์ ๋ฃ๋๋ค. craft_send.c ์ struct pseudo ๊ฐ ๊ทธ๊ฒ์ด๋ค.
๐ ํ์
๋ค ๊ฐ์ง ๊ทผ๊ฑฐ๋ฅผ ํ ์คํฌ๋ฆฝํธ๋ก ๋ฌถ์ด ๋๋ฉด ๋์ค์ ํด๋๋ง ์ด์ด๋ ๊ฒฐ๋ก ์ด ์ฌํ๋๋ค.
#!/usr/bin/env python3
"""solve.py โ 03.txt ๊ฐ ๋ฌด์จ ํจ์์ธ์ง ์ค์ธก์ผ๋ก ํ์ ํ๊ณ ์ ๋ต ํ ๋จ์ด๋ฅผ ์ถ๋ ฅํ๋ค.
๋ฌธ์ ๋ "๋ฌด์์ ํ๋ ํจ์์ธ๊ฐ"๋ฅผ ๋ฌป๋๋ค. ๋์ผ๋ก ๋ณด๊ณ '์ฒดํฌ์ฌ ๊ฐ๋ค'๋ก ๋๋ด์ง ์๊ณ
์๋ ๋ค ๊ฐ์ง๋ฅผ ์ค์ ๋ก ๋๋ ค์ ๊ฒฐ๋ก ์ ๋ธ๋ค.
[1] RFC 1071 ์ด ๋ฌธ์์ ์ง์ ์ ์ด ๋ ์์ ์ ๋ง๋๊ฐ
[2] ๊ต๊ณผ์ IP ํค๋ ์์ ์ ๋ง๋๊ฐ
[3] tcpdump ๋ก ์ก์ ์ง์ง ํจํท์ IPยทICMP ์ฒดํฌ์ฌ ์๋ฆฌ๋ฅผ ๊ทธ๋๋ก ์ฌํํ๋๊ฐ
[4] ๋ฌด์์ ์
๋ ฅ 200๊ฐ์์ ๊ท๊ฒฉ ๊ตฌํ๊ณผ ํ ๋นํธ๋ ์ ์ด๊ธ๋๋๊ฐ (์ง์ ๊ธธ์ด)
๋ท ๋ค ํต๊ณผํด์ผ ๋ต์ ์ฐ๋๋ค. ํ๋๋ผ๋ ์ด๊ธ๋๋ฉด ์ด์ ๋ฅผ ์ ๊ณ ์ข
๋ฃ์ฝ๋ 1 ๋ก ๋๋ธ๋ค.
"""
import random
import struct
import subprocess
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
from reference import rfc1071, to_wire # noqa: E402
BIN = HERE / "cksum"
PCAP = HERE / "live_icmp.pcap"
def build():
subprocess.run(["gcc", "-O0", "-g", "-Wall", "-Wextra", "-o", str(BIN),
str(HERE / "snippet.c"), str(HERE / "driver.c")], check=True)
def snippet(raw: bytes) -> int:
"""์ปดํ์ผํ ๋ฐฐํฌ๋ณธ ํจ์๋ฅผ ์คํํ๊ณ , ์ ์ (๋น
์๋์ธ) ์์๋ก ๋ฐ๊ฟ ๋๋ ค์ค๋ค."""
out = subprocess.run([str(BIN), raw.hex()], capture_output=True, text=True, check=True).stdout
return to_wire(int(out.split("=")[-1], 16))
def pcap_packets(path: Path):
blob = path.read_bytes()
endian = "<" if blob[:4] in (b"\xd4\xc3\xb2\xa1", b"\x4d\x3c\xb2\xa1") else ">"
linktype = struct.unpack(endian + "I", blob[20:24])[0]
l2 = {0: 4, 1: 14, 113: 16, 101: 0}.get(linktype, 14)
off = 24
while off + 16 <= len(blob):
_, _, caplen, _ = struct.unpack(endian + "IIII", blob[off:off + 16])
yield blob[off + 16 + l2: off + 16 + caplen]
off += 16 + caplen
ok = True
print("[1] RFC 1071 3์ฅ ์์ (00 01 f2 03 f4 f5 f6 f7)")
build()
got = snippet(bytes.fromhex("0001f203f4f5f6f7"))
print(f" RFC ๋ฌธ์๊ฐ ์ ์ 1์ ๋ณด์ ํฉ 0xddf2 -> ๊ทธ ๋ณด์ 0x220d ๊ฐ ์ฒดํฌ์ฌ")
print(f" ๋ฐฐํฌ๋ณธ=0x{got:04x} ->", "์ผ์น" if got == 0x220D else "๋ถ์ผ์น")
ok &= got == 0x220D
print("[2] IP ํค๋ ์์ (์ฒดํฌ์ฌ ํ๋๋ฅผ 0 ์ผ๋ก ๋ 20๋ฐ์ดํธ)")
hdr = bytes.fromhex("4500003c1c46400040060000ac100a63ac100a0c")
got = snippet(hdr)
print(f" ๋ฐฐํฌ๋ณธ=0x{got:04x} ๊ธฐ๋๊ฐ=0xb1e6 ->", "์ผ์น" if got == 0xB1E6 else "๋ถ์ผ์น")
ok &= got == 0xB1E6
print(f"[3] ์ค์ ๋ก ์ ์ ์ ์ง๋๊ฐ ํจํท ({PCAP.name})")
if not PCAP.exists():
print(" pcap ์ด ์๋ค. ./capture_live.sh ๋ฅผ ๋จผ์ ๋๋ฆฐ๋ค.")
ok = False
else:
n = miss = 0
for ip in pcap_packets(PCAP):
if not ip or ip[0] >> 4 != 4:
continue
ihl = (ip[0] & 0xF) * 4
hdr, payload = ip[:ihl], ip[ihl:]
n += 1
if snippet(hdr[:10] + b"\x00\x00" + hdr[12:]) != struct.unpack("!H", hdr[10:12])[0]:
miss += 1
if hdr[9] == 1 and len(payload) >= 4:
n += 1
if snippet(payload[:2] + b"\x00\x00" + payload[4:]) != struct.unpack("!H", payload[2:4])[0]:
miss += 1
print(f" ์ฒดํฌ์ฌ ์๋ฆฌ {n}๊ณณ ์ค {n - miss}๊ณณ ์ฌํ, ์ด๊ธ๋ ๊ณณ {miss}")
ok &= n > 0 and miss == 0
print("[4] ๋ฌด์์ ์ง์ ๊ธธ์ด 200๊ฐ โ ๊ท๊ฒฉ ๊ตฌํ๊ณผ ์ ์ ๋์กฐ")
random.seed(1071)
miss = 0
for _ in range(200):
raw = bytes(random.randrange(256) for _ in range(random.randrange(1, 300) * 2))
if snippet(raw) != rfc1071(raw):
miss += 1
print(f" ๋ถ์ผ์น {miss} / 200")
ok &= miss == 0
print()
if ok:
print("๊ฒฐ๋ก : 03.txt ๋ RFC 1071 ์ธํฐ๋ท ์ฒดํฌ์ฌ(in_cksum) ์ด๋ค.")
print(" IP_HDRINCL ๋ก์ฐ์์ผ์ผ๋ก ํค๋๋ฅผ ์ง์ ๋ง๋๋ ์ฝ๋๊ฐ ์ปค๋ ๋์ ์ฑ์์ผ ํ๋ ๊ฐ์ด๋ค.")
print()
print("FLAG: checksum")
else:
print("๊ฒฐ๋ก ๋ณด๋ฅ โ ์์์ ์ด๊ธ๋ ํญ๋ชฉ์ ๋จผ์ ํ์ธํ ๊ฒ")
sys.exit(1)python3 solve.py
์ ๋ต์ checksum. CodeEngn ๋ฌธ์ ๋ผ DH ๋ก ์์ํ๋ ๋ํผ๋ ์๊ณ ์๋ฌธ์ ํ ๋จ์ด๋ฅผ ๊ทธ๋๋ก ์ ์ถํ๋ค.
crc ๋ฅผ ๋ ์ฌ๋ ธ๋ค๋ฉด ๋ฐฉํฅ์ด ๋ค๋ฅด๋ค. CRC ๋ ๋คํญ์ ๋๋์
์ด๊ณ , ์ด ์ฝ๋์๋ ๋๋์
๋ ์ํํธ ๋ ์ง์คํฐ๋ ์๋ค. ์ฌ๊ธฐ ์๋ ๊ฑด ๋ง์
๊ณผ ๋ณด์๋ฟ์ด๋ค.
๐ ๊ฒฐ๋ก
๋ชจ์์ด ๊ฐ๋ค๊ณ ๊ฐ์ ๋ฌผ๊ฑด์ ์๋๋ค.
"1์ ๋ณด์ ํฉ์ ๋ณด์" ๋ผ๋ ํํ๋ง ๋ณด๊ณ ๋ ๋ต์ ์ฐ์ ์ ์์๋ค. ํ์ง๋ง ๊ทธ๊ฑด ๋ต์ ๋งํ๋ ๊ฒ์ด์ง ํ์ ํ๋ ๊ฒ ์๋๋ค. ๋ฐฐํฌ๋ณธ์ ๊ทธ๋๋ก ์ปดํ์ผํด ์ค์ ํจํท์ ์ฒดํฌ์ฌ ์๋ฆฌ 12๊ณณ๊ณผ ๋ง์ถฐ ๋ณด๊ณ ๋์์ผ ๊ทผ๊ฑฐ๊ฐ ์๊ฒผ๋ค. ์ฝ๋ ์กฐ๊ฐ ํ๋๋ฅผ ๋ฐ์์ ๋ ๊ฐ์ฅ ๋น ๋ฅธ ํ์ธ ์๋จ์ ๋์ฒด๋ก "๊ทธ๋๋ก ๋๋ ค ๋ณด๋ ๊ฒ"์ด๋ค.
๋ฐ์ดํธ ์์๋ฅผ ๊ฒฐ๊ณผ๊ฐ ์๋๋ผ ์ ์ฅ ์์ ์์ ๋ด์ผ ํ๋ค.
0x0d22 ์ 220d ๋ฅผ ๋ณด๊ณ ์ฒ์์ ๋ถ์ผ์น๋ก ํ๋จํ๋ค. ํ๋ฉด์ ์ฐํ 16์ง์๋ ์์น์ผ ๋ฟ์ด๊ณ , ์ ์ ์ ๋๊ฐ๋ ๊ฒ์ ๊ทธ ์์น๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ผ์ ๋์ ๋ฐ์ดํธ๋ค. ํธ์คํธ ์์๋ก ๋ํด์ ๊ทธ๋๋ก ์ ์ฅํ๋ฉด ๊ฒฐ๊ณผ๊ฐ ๋ง๋๋ค๋ ๊ฒ ์ธํฐ๋ท ์ฒดํฌ์ฌ์ ์ค๊ณ ์๋์ด๊ธฐ๋ ํ๋ค.
์ด๊ธฐํ ๋๋ฝ์ ์ฐ์ฐํ ๋ง์ ์ ์์ด์ ๋ ์ํํ๋ค.
-O0 ๋น๋๋ ๊ฒฝ๊ณ ๋ ์์ด ์ ๋ต์ ๋๋ค. rbx ์ ๋ง์นจ 0์ด ๋ค์ด ์์์ ๋ฟ์ด๋ค. ํธ์ถ ๊ฒฝ๋ก๊ฐ ๋ฐ๋๋ฉด ์กฐ์ฉํ ํ๋ฆฐ ๊ฐ์ ๋ด๊ธฐ ์์ํ๋ค. ์ ์ฝ๋์ -Wall -Wextra ๋ง ๊ฑธ์ด ๋๊ณ ์์ฌํ์ง ๋ง๊ณ ์ต์ ํ๋ฅผ ์ผ ๋น๋๋ ํ ๋ฒ์ ๋๋ ค ๋ณด๋ ๊ฒ ๋ซ๋ค.
๋ฐฉ์ด ๊ด์ ์์ ์ด ํจ์๋ ์ข์ ํ์ง ์งํ๋ค.
์ผ๋ฐ ์์ฉ ํ๋ก๊ทธ๋จ์ ์ฒดํฌ์ฌ์ ์ง์ ๊ณ์ฐํ ์ผ์ด ์๋ค. ์ปค๋์ด ํด ์ค๋ค. ์ฌ์ฉ์ ์์ญ ๋ฐ์ด๋๋ฆฌ์์ RFC 1071 ํํ์ ๋ฃจํด์ด ๋ฐ๊ฒฌ๋๊ณ ๊ทธ ์์ SOCK_RAW ์ IP_HDRINCL ์ด ๊ฐ์ด ์๋ค๋ฉด, ๊ทธ๊ฑด ์ถ๋ฐ์ง๋ฅผ ์์กฐํ ํจํท์ ๋ง๋ค๊ฒ ๋ค๋ ๋ป์ด๋ค. ๋คํธ์ํฌ ์ชฝ์์๋ ๊ฒฝ๊ณ์์ uRPF ๋ BCP 38 ๊ณ์ด์ ์ถ๋ฐ์ง ์ฃผ์ ํํฐ๋ง์ ์ผ ๋๋ฉด ์์กฐ๋ ์ถ๋ฐ์ง ํจํท์ด ๋ฐ์ผ๋ก ๋๊ฐ๋ ๊ฒ์ ๋ง์ ์ ์๋ค.
๊ฐ์ ํํ์ ์ฝ๋๊ฐ ๋ฐ๋์ ๊ท๊ฒฉ๋๋ก์ธ ๊ฒ์ ์๋๋ค.
์ด ๋ฐ์ท๋ณธ์ ํ์ ๊ธธ์ด์์ ๋ฉ์์ง ๋ฐ 1๋ฐ์ดํธ๋ฅผ ์ฝ๊ณ , 6๋ฐ์ดํธ ์ ๋ ฅ์์ ์ด๋ฏธ ์บ๋ฆฌ ํ๋๋ฅผ ํ๋ฆฐ๋ค. ์ธํฐ๋ท์ ๊ตด๋ฌ๋ค๋๋ ์ฒดํฌ์ฌ ์ค๋ํซ์ ๊ทธ๋๋ก ๋ณต์ฌํด ์ธ ๋ ํํ ๋ฐ๋ผ์ค๋ ๋ฌธ์ ๋ค. ์ฌ๊ตฌํํ๊ธฐ ์ ์ ๊ท๊ฒฉ ๋ฌธ์์ ์์ ๋ฒกํฐ๋ก ํ ๋ฒ ์ฌ ๋ณด๋ฉด ๋๋ถ๋ถ ์ด ์๋ฆฌ์์ ๊ฑธ๋ฆฐ๋ค.
Comments
๋๊ธ
๋๊ธ์ ๋จ๊ธฐ๋ ค๋ฉด ๋ก๊ทธ์ธ์ด ํ์ํด์. (๋ค์ด๋ฒ ยท ๊ตฌ๊ธ ๊ณ์ )
๋๊ธ ๋ถ๋ฌ์ค๋ ์คโฆ