HackTheBox Walkthrough - GitHappens¶
Machine ciblée : GitHappens.
Répertoire : /home/kali/GitHappens
Temps passé dessus : 1h20.
Changelog du template¶
Version 1.0 - Sep. 2022 : création du template de base
Version 1.1 - Oct. 2022 : Rajout des scan nmap et des commandes de base
Version 1.2 - Nov. 2022 : Rajout des redirection pour éviter les retours d’erreur et du domaine pour être compliant avec TryHackMe
Version 1.3 - Nov. 2022 : Ajout du scan UDP + de l’export vers searchsploit
Version 1.4 - Dec. 2022 : Changement de l’export vers searchsploit pour gagner du temps + rajout des scripts vuln sur le full pour confirmer.
Phase 1 : Reconnaissance¶
┌──(kali㉿kali)-[~]
└─$
name="GitHappens"
repository="/home/kali/$name"
ip="10.10.203.188"
domain='thm'
cd $repository 2&>/dev/null || mkdir $repository && cd $repository
grep "$ip $name ${name}.${domain}" /etc/hosts >/dev/null || echo "$ip $name ${name}.${domain}" | sudo tee -a /etc/hosts
nmap -Pn -A -T5 --top-port 1000 -oN $repository/txt -oX $repository/sploitable $ip
searchsploit --nmap $repository/sploitable
nmap -Pn -A -T5 -p - --script vuln -oN $repository/full -oX $repository/fullsploitable $ip
sudo nmap -Pn -A -T5 -sU -p - -oN $repository/udp -oX $repository/udploitable $ip
searchsploit --nmap $repository/udploitable
PORT STATE SERVICE VERSION
80/tcp open http nginx 1.14.0 (Ubuntu)
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Super Awesome Site!
| http-git:
| 10.10.203.188:80/.git/
| Git repository found!
|_ Repository description: Unnamed repository; edit this file 'description' to name the...
163/tcp filtered cmip-man
301/tcp filtered unknown
777/tcp filtered multiling-http
1033/tcp filtered netinfo
2020/tcp filtered xinupageserver
2111/tcp filtered kx
3077/tcp filtered orbix-loc-ssl
3827/tcp filtered netmpi
5850/tcp filtered unknown
5950/tcp filtered unknown
7103/tcp filtered unknown
7402/tcp filtered rtps-dd-mt
7778/tcp filtered interwise
8402/tcp filtered abarsd
9091/tcp filtered xmltec-xmlmail
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.82 seconds
[i] SearchSploit s XML mode (without verbose enabled). To enable: searchsploit -v --xml...
[i] Reading: '/home/kali/GitHappens/sploitable'
[-] Skipping term: http (Term is too general. Please re-search manually: /usr/bin/searchsploit -t http)
[i] /usr/bin/searchsploit -t nginx
-------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
-------------------------------------------------------------------------------------------------- ---------------------------------
Nginx (Debian Based Distros + Gentoo) - 'logrotate' Local Privilege Escalation | linux/local/40768.sh
Nginx 0.6.36 - Directory Traversal | multiple/remote/12804.txt
Nginx 0.6.38 - Heap Corruption | linux/local/14830.py
Nginx 0.6.x - Arbitrary Code Execution NullByte Injection | multiple/webapps/24967.txt
Nginx 0.7.0 < 0.7.61 / 0.6.0 < 0.6.38 / 0.5.0 < 0.5.37 / 0.4.0 < 0.4.14 - Denial of Service (PoC) | linux/dos/9901.txt
Nginx 0.7.61 - WebDAV Directory Traversal | multiple/remote/9829.txt
Nginx 0.7.64 - Terminal Escape Sequence in Logs Command Injection | multiple/remote/33490.txt
Nginx 0.7.65/0.8.39 (dev) - Source Disclosure / Download | windows/remote/13822.txt
Nginx 0.8.36 - Source Disclosure / Denial of Service | windows/remote/13818.txt
Nginx 1.1.17 - URI Processing SecURIty Bypass | multiple/remote/38846.txt
Nginx 1.20.0 - Denial of Service (DOS) | multiple/remote/50973.py
Nginx 1.3.9 < 1.4.0 - Chuncked Encoding Stack Buffer Overflow (Metasploit) | linux/remote/25775.rb
Nginx 1.3.9 < 1.4.0 - Denial of Service (PoC) | linux/dos/25499.py
Nginx 1.3.9/1.4.0 (x86) - Brute Force | linux_x86/remote/26737.pl
Nginx 1.4.0 (Generic Linux x64) - Remote Overflow | linux_x86-64/remote/32277.txt
PHP-FPM + Nginx - Remote Code Execution | php/webapps/47553.md
-------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
[i] /usr/bin/searchsploit -t cmip man
[-] Skipping term: unknown (Term is too general. Please re-search manually: /usr/bin/searchsploit -t unknown)
[i] /usr/bin/searchsploit -t multiling http
[i] /usr/bin/searchsploit -t netinfo
[i] /usr/bin/searchsploit -t xinupageserver
[i] /usr/bin/searchsploit -t kx
-------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
-------------------------------------------------------------------------------------------------- ---------------------------------
BookmarkX script 2007 - 'topicid' SQL Injection | php/webapps/5040.txt
CityPost PHP LNKX 52.0 - 'message.php' Cross-Site Scripting | php/webapps/25458.txt
KingScada - kxClientDownload.ocx ActiveX Remote Code Execution (Metasploit) | windows/remote/31575.rb
Mitsubishi MC-WorkX 8.02 - ActiveX Control 'IcoLaunch' File Execution | windows/remote/28284.html
NX5Linkx 1.0 - 'links.php' HTTP Response Splitting | php/webapps/28568.txt
NX5Linkx 1.0 - Multiple SQL Injections | php/webapps/28567.txt
WordPress Plugin BookX 1.7 - 'bookx_export.php' Local File Inclusion | php/webapps/39251.txt
-------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
[i] /usr/bin/searchsploit -t orbix loc ssl
[i] /usr/bin/searchsploit -t netmpi
[i] /usr/bin/searchsploit -t rtps dd mt
[i] /usr/bin/searchsploit -t interwise
[i] /usr/bin/searchsploit -t abarsd
On a donc un premier site web qui s’avère être un git. Il est peut-être possible de reconstruire le site à partir de ça. Pour ceux qui veulent un peu plus d’explication, on en trouve par ici.
┌──(kali㉿kali)-[~/GitHappens]
└─$ mkdir gited && cd gited
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ wget --recursive --no-parent http://${name}/.git/
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ mv githappens/.git ./
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ rm -R githappens
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ git status
Sur la branche master
Modifications qui ne seront pas validées :
(utilisez "git add/rm <fichier>..." pour mettre à jour ce qui sera validé)
(utilisez "git restore <fichier>..." pour annuler les modifications dans le répertoire de travail)
supprimé : .gitlab-ci.yml
supprimé : Dockerfile
supprimé : README.md
supprimé : css/style.css
supprimé : dashboard.html
supprimé : default.conf
supprimé : index.html
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ git checkout -- . #Je la connaissais pas elle, elle est plutôt pratique !
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ ls
css dashboard.html default.conf Dockerfile index.html README.md
On a donc récupérer le code du site. Analysons.
Phase 2 : Analyse¶
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ cat index.html
<script>
const _0x4368=['+(\x20+[^','471197','value','RegExp','functi','test','CbRnH','passwo','userna','TML','tml','a865c5','+[^\x20]}','a5f298','cookie','admin','3a71fd','getEle','login-','^([^\x20]','TEhxP','href','f64cb3','51a151','d84319','D\x20USER','digest','R\x20PASS','oard.h','error','\x20]+)+)','19a3c0','f80f67','/dashb','bea070','3ec9cb','padSta','from','4004c2','WORD!','map','NAME\x20O','encode','INVALI','a5106e','baf89f','6a7c7c','elemen','9a88db','log','join','innerH','SaltyB','apply','ned','442a9d','mentBy'];(function(_0x1ef2d8,_0x436806){const _0x2c2818=function(_0x302738){while(--_0x302738){_0x1ef2d8['push'](_0x1ef2d8['shift']());}},_0x6f8b4a=function(){const _0x2e9681={'data':{'key':'cookie','value':'timeout'},'setCookie':function(_0x329b53,_0x28dc3d,_0x22f4a3,_0x6012c1){_0x6012c1=_0x6012c1||{};let _0x3d8f23=_0x28dc3d+'='+_0x22f4a3,_0x18026e=0x0;for(let _0x4175c9=0x0,_0x25d1be=_0x329b53['length'];_0x4175c9<_0x25d1be;_0x4175c9++){const _0x109e81=_0x329b53[_0x4175c9];_0x3d8f23+=';\x20'+_0x109e81;const _0x1e9a27=_0x329b53[_0x109e81];_0x329b53['push'](_0x1e9a27),_0x25d1be=_0x329b53['length'],_0x1e9a27!==!![]&&(_0x3d8f23+='='+_0x1e9a27);}_0x6012c1['cookie']=_0x3d8f23;},'removeCookie':function(){return'dev';},'getCookie':function(_0x3e797a,_0x2a5b7d){_0x3e797a=_0x3e797a||function(_0x242cdf){return _0x242cdf;};const _0x996bc1=_0x3e797a(new RegExp('(?:^|;\x20)'+_0x2a5b7d['replace'](/([.$?*|{}()[]\/+^])/g,'$1')+'=([^;]*)')),_0x51d0ee=function(_0x439650,_0x52fa41){_0x439650(++_0x52fa41);};return _0x51d0ee(_0x2c2818,_0x436806),_0x996bc1?decodeURIComponent(_0x996bc1[0x1]):undefined;}},_0x17997b=function(){const _0x383e88=new RegExp('\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*[\x27|\x22].+[\x27|\x22];?\x20*}');return _0x383e88['test'](_0x2e9681['removeCookie']['toString']());};_0x2e9681['updateCookie']=_0x17997b;let _0x39ee22='';const _0xad377=_0x2e9681['updateCookie']();if(!_0xad377)_0x2e9681['setCookie'](['*'],'counter',0x1);else _0xad377?_0x39ee22=_0x2e9681['getCookie'](null,'counter'):_0x2e9681['removeCookie']();};_0x6f8b4a();}(_0x4368,0xe6));const _0x2c28=function(_0x1ef2d8,_0x436806){_0x1ef2d8=_0x1ef2d8-0x0;let _0x2c2818=_0x4368[_0x1ef2d8];return _0x2c2818;};const _0x22f4a3=function(){let _0x36b504=!![];return function(_0x1087c7,_0x108f32){if(_0x2c28('0x4')===_0x2c28('0x4')){const _0x52d1da=_0x36b504?function(){if(_0x2c28('0x12')!==_0x2c28('0x12')){function _0x382a78(){document[_0x2c28('0xf')+_0x2c28('0x36')+'Id'](_0x2c28('0x1b'))['innerH'+_0x2c28('0x7')]=_0x2c28('0x29')+_0x2c28('0x17')+'NAME\x20O'+_0x2c28('0x19')+_0x2c28('0x25');}}else{if(_0x108f32){const _0x725292=_0x108f32[_0x2c28('0x33')](_0x1087c7,arguments);return _0x108f32=null,_0x725292;}}}:function(){};return _0x36b504=![],_0x52d1da;}else{function _0x323170(){const _0x2ed5f9=_0x36b504?function(){if(_0x108f32){const _0x407994=_0x108f32[_0x2c28('0x33')](_0x1087c7,arguments);return _0x108f32=null,_0x407994;}}:function(){};return _0x36b504=![],_0x2ed5f9;}}};}(),_0x28dc3d=_0x22f4a3(this,function(){const _0x5b8de6=typeof window!=='undefi'+_0x2c28('0x34')?window:typeof process==='object'&&typeof require===_0x2c28('0x2')+'on'&&typeof global==='object'?global:this,_0x4d9f75=function(){const _0x1eee2f=new _0x5b8de6[(_0x2c28('0x1'))](_0x2c28('0x11')+_0x2c28('0x37')+_0x2c28('0x1c')+_0x2c28('0xa'));return!_0x1eee2f[_0x2c28('0x3')](_0x28dc3d);};return _0x4d9f75();});_0x28dc3d();async function login(){let _0x110afb=document[_0x2c28('0xf')+_0x2c28('0x36')+'Id'](_0x2c28('0x10')+'form');console[_0x2c28('0x2f')](_0x110afb[_0x2c28('0x2d')+'ts']);let _0x383cb8=_0x110afb[_0x2c28('0x2d')+'ts'][_0x2c28('0x6')+'me'][_0x2c28('0x0')],_0x5b6063=await digest(_0x110afb[_0x2c28('0x2d')+'ts'][_0x2c28('0x5')+'rd'][_0x2c28('0x0')]);_0x383cb8===_0x2c28('0xd')&&_0x5b6063===_0x2c28('0x24')+_0x2c28('0xe')+'6ba9b0'+_0x2c28('0x21')+'7eed08'+_0x2c28('0x38')+_0x2c28('0x16')+_0x2c28('0x9')+_0x2c28('0x35')+_0x2c28('0x2c')+_0x2c28('0x20')+'f3cb6a'+_0x2c28('0x2a')+_0x2c28('0x1e')+_0x2c28('0x2e')+_0x2c28('0x2b')+_0x2c28('0x14')+_0x2c28('0x15')+_0x2c28('0xb')+_0x2c28('0x1d')+'94eceb'+'bb'?(document[_0x2c28('0xc')]='login='+'1',window['locati'+'on'][_0x2c28('0x13')]=_0x2c28('0x1f')+_0x2c28('0x1a')+_0x2c28('0x8')):document['getEle'+_0x2c28('0x36')+'Id'](_0x2c28('0x1b'))[_0x2c28('0x31')+_0x2c28('0x7')]=_0x2c28('0x29')+_0x2c28('0x17')+_0x2c28('0x27')+_0x2c28('0x19')+_0x2c28('0x25');}async function digest(_0x35521d){const _0x179c00=new TextEncoder(),_0x713734=_0x179c00[_0x2c28('0x28')](_0x35521d+(_0x2c28('0x32')+'ob')),_0x39b76f=await crypto['subtle'][_0x2c28('0x18')]('SHA-51'+'2',_0x713734),_0x558ac0=Array[_0x2c28('0x23')](new Uint8Array(_0x39b76f)),_0x34e00e=_0x558ac0[_0x2c28('0x26')](_0x468ec7=>_0x468ec7['toStri'+'ng'](0x10)[_0x2c28('0x22')+'rt'](0x2,'0'))[_0x2c28('0x30')]('');return _0x34e00e;}
</script>
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ cat dashboard.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Awesome!</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body onload="checkCookie()">
<p class="rainbow-text">Awesome! Use the password you input as the flag!</p>
<script>
var _0x13f2=['The\x20co','test','href','okie\x20\x22','RegExp','locati','+[^\x20]}','\x20value','hvvqf','split','apply','\x20has\x20\x22','UmvzZ','+(\x20+[^','undefi','includ','functi','/index','object','login\x22','BzWoi','JSjhF','1\x22\x20for','.html','log'];(function(_0x25afd6,_0x13f2ae){var _0x293e02=function(_0x39bb51){while(--_0x39bb51){_0x25afd6['push'](_0x25afd6['shift']());}},_0x4e9f94=function(){var _0x664dc3={'data':{'key':'cookie','value':'timeout'},'setCookie':function(_0x5504a4,_0x228943,_0x1cdb91,_0x1e9670){_0x1e9670=_0x1e9670||{};var _0x39bcf8=_0x228943+'='+_0x1cdb91,_0x53f475=0x0;for(var _0x13cc7b=0x0,_0x264136=_0x5504a4['length'];_0x13cc7b<_0x264136;_0x13cc7b++){var _0x44c799=_0x5504a4[_0x13cc7b];_0x39bcf8+=';\x20'+_0x44c799;var _0x42ecce=_0x5504a4[_0x44c799];_0x5504a4['push'](_0x42ecce),_0x264136=_0x5504a4['length'],_0x42ecce!==!![]&&(_0x39bcf8+='='+_0x42ecce);}_0x1e9670['cookie']=_0x39bcf8;},'removeCookie':function(){return'dev';},'getCookie':function(_0x1baf49,_0x45f075){_0x1baf49=_0x1baf49||function(_0x2f4c45){return _0x2f4c45;};var _0x19df86=_0x1baf49(new RegExp('(?:^|;\x20)'+_0x45f075['replace'](/([.$?*|{}()[]\/+^])/g,'$1')+'=([^;]*)')),_0x264820=function(_0x344491,_0x554a27){_0x344491(++_0x554a27);};return _0x264820(_0x293e02,_0x13f2ae),_0x19df86?decodeURIComponent(_0x19df86[0x1]):undefined;}},_0x1feb05=function(){var _0x16aab2=new RegExp('\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*[\x27|\x22].+[\x27|\x22];?\x20*}');return _0x16aab2['test'](_0x664dc3['removeCookie']['toString']());};_0x664dc3['updateCookie']=_0x1feb05;var _0x4984a0='';var _0x29b714=_0x664dc3['updateCookie']();if(!_0x29b714)_0x664dc3['setCookie'](['*'],'counter',0x1);else _0x29b714?_0x4984a0=_0x664dc3['getCookie'](null,'counter'):_0x664dc3['removeCookie']();};_0x4e9f94();}(_0x13f2,0x102));var _0x293e=function(_0x25afd6,_0x13f2ae){_0x25afd6=_0x25afd6-0x0;var _0x293e02=_0x13f2[_0x25afd6];return _0x293e02;};var _0x1cdb91=function(){var _0x371b4e=!![];return function(_0x595c10,_0x69462f){var _0x2b09a3=_0x371b4e?function(){if(_0x69462f){if(_0x293e('0x4')!==_0x293e('0x0')){var _0x97fad5=_0x69462f[_0x293e('0x2')](_0x595c10,arguments);return _0x69462f=null,_0x97fad5;}else{function _0x38efef(){var _0x850131=_0x371b4e?function(){if(_0x69462f){var _0x568ca6=_0x69462f[_0x293e('0x2')](_0x595c10,arguments);return _0x69462f=null,_0x568ca6;}}:function(){};return _0x371b4e=![],_0x850131;}}}}:function(){};return _0x371b4e=![],_0x2b09a3;};}(),_0x228943=_0x1cdb91(this,function(){var _0x3b903a=typeof window!==_0x293e('0x6')+'ned'?window:typeof process===_0x293e('0xa')&&typeof require===_0x293e('0x8')+'on'&&typeof global==='object'?global:this,_0x2859ed=function(){if(_0x293e('0xd')!==_0x293e('0xc')){var _0x1ea358=new _0x3b903a[(_0x293e('0x15'))]('^([^\x20]'+_0x293e('0x5')+'\x20]+)+)'+_0x293e('0x17'));return!_0x1ea358[_0x293e('0x12')](_0x228943);}else{function _0x454428(){console[_0x293e('0x10')](_0x293e('0x11')+_0x293e('0x14')+_0x293e('0xb')+'\x20has\x20\x22'+'1\x22\x20for'+_0x293e('0x18'));}}};return _0x2859ed();});_0x228943();function checkCookie(){document['cookie'][_0x293e('0x1')](';')['some'](_0x5b421e=>_0x5b421e[_0x293e('0x7')+'es']('login='+'1'))?console[_0x293e('0x10')](_0x293e('0x11')+_0x293e('0x14')+_0x293e('0xb')+_0x293e('0x3')+_0x293e('0xe')+_0x293e('0x18')):window[_0x293e('0x16')+'on'][_0x293e('0x13')]=_0x293e('0x9')+_0x293e('0xf');}
</script>
</body>
</html>
À première vue, on a donc une première page qui est authentifiée par un mot de passe puis une seconde qui nous dis que le mot de passe est le flag. On peut devinier que le mot de passe est contenu dans la constante ignoble et ilisible. Perso, j’suis pas un habitué du javascript … Alors regardons comment s’est déroulé le projet.
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ git log
commit d0b3578a628889f38c0affb1b75457146a4678e5 (HEAD -> master, tag: v1.0)
Author: Adam Bertrand <hydragyrum@gmail.com>
Date: Thu Jul 23 22:22:16 2020 +0000
Update .gitlab-ci.yml
commit 77aab78e2624ec9400f9ed3f43a6f0c942eeb82d
Author: Hydragyrum <hydragyrum@gmail.com>
Date: Fri Jul 24 00:21:25 2020 +0200
add gitlab-ci config to build docker file.
commit 2eb93ac3534155069a8ef59cb25b9c1971d5d199
Author: Hydragyrum <hydragyrum@gmail.com>
Date: Fri Jul 24 00:08:38 2020 +0200
setup dockerfile and setup defaults.
commit d6df4000639981d032f628af2b4d03b8eff31213
Author: Hydragyrum <hydragyrum@gmail.com>
Date: Thu Jul 23 23:42:30 2020 +0200
Make sure the css is standard-ish!
commit d954a99b96ff11c37a558a5d93ce52d0f3702a7d
Author: Hydragyrum <hydragyrum@gmail.com>
Date: Thu Jul 23 23:41:12 2020 +0200
re-obfuscating the code to be really secure!
commit bc8054d9d95854d278359a432b6d97c27e24061d
Author: Hydragyrum <hydragyrum@gmail.com>
Date: Thu Jul 23 23:37:32 2020 +0200
Security says obfuscation isn t enough.
They want me to use something called 'SHA-512'
commit e56eaa8e29b589976f33d76bc58a0c4dfb9315b1
Author: Hydragyrum <hydragyrum@gmail.com>
Date: Thu Jul 23 23:25:52 2020 +0200
Obfuscated the source code.
Hopefully security will be happy!
commit 395e087334d613d5e423cdf8f7be27196a360459
Author: Hydragyrum <hydragyrum@gmail.com>
Date: Thu Jul 23 23:17:43 2020 +0200
Made the login page, boss!
commit 2f423697bf81fe5956684f66fb6fc6596a1903cc
Author: Adam Bertrand <hydragyrum@gmail.com>
Date: Mon Jul 20 20:46:28 2020 +0000
Initial commit
On voit donc ici que le code source a été offusqué à partir du commit e56eaa8e29b589976f33d76bc58a0c4dfb9315b1. Revenons avant celui là pour voir …
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ git checkout 395e087334d613d5e423cdf8f7be27196a360459 .
3 chemins mis à jour depuis ba5e4a7
┌──(kali㉿kali)-[~/GitHappens/gited]
└─$ cat index.html
<script>
function login() {
let form = document.getElementById("login-form");
console.log(form.elements);
let username = form.elements["username"].value;
let password = form.elements["password"].value;
if (
username === "admin" &&
password === "Th1s_1s_4_L0ng_4nd_S3cur3_P4ssw0rd!"
) {
document.cookie = "login=1";
window.location.href = "/dashboard.html";
} else {
document.getElementById("error").innerHTML =
"INVALID USERNAME OR PASSWORD!";
}
}
</script>
On récupère donc le mot de passe ici qui se révèle être également le flag ! Th1s_1s_4_L0ng_4nd_S3cur3_P4ssw0rd!
Récapitulatif¶
Je suis un peu parti tête baisée sur du reverse de javascript parce que c’était le test d’entrée de Hack The Box à l’époque … J’aurai sans doute du me poser un poil plus et réfléchir au fait que la box était sur git. J’ai ouvert un write-up pour voir qu’il partait dans le git log et j’ai de suite pigé. J’aimerai bien voir le même exercice avec un git log complètement refet et où il faudrait partir dans le reflog. Ça serait un beau petit plus pour un autre chall.
A retenir¶
Git Checkout permet de se balader dans l’historique git très facilement.
On peut reconstruire un git depuis ses fichiers objetcs …
Faire extrèmement attention à l’historique d’un git.