picoCTF 2021 Milkslap Writeup

Milkslap is a forensics puzzle worth 120 points.

The description is just an emoji of a glass of milk, which links to http://mercury.picoctf.net:29522/ and plays an animation of a person standing in a shower getting a glass of milk splashed in their face as you move the mouse over the picture.

Viewing the source revealed a small amount of html, linking to another site eelslap.com which is similar to this milkslap site, but the gentleman is getting hit in the face with an eel instead of a glass of milk. It also links to boxmein‘s GitHub page for inspiring the code in this challenge.

The script included in this site is a straightforward JavaScript file that recalculates the position of the background based on the mouse cursor’s location over the page. Nothing stood out as being part of the flag:

var currentX = 0;
var tweenedPageX = 0;
var background_y = 0;
var frame_num = 0;
var background_max = 46800;
var image = document.getElementById("image");
var image_bcr = image.getBoundingClientRect();
var image_right_coord = 0;
var image_left_coord = 0;
var mouse_depth = 0;
var frame_ht = 720;
var mousepct = 0;
var frameinterval =  0.016;
var totalX = window.outerWidth;

function animate(e){
  image_right_coord = image_bcr.right;
  image_left_coord = image_bcr.left;
  currentX = e.x;
  mouse_depth = Math.max(image_right_coord - currentX, 0);

  mousepct = mouse_depth / image_bcr.width;  
  frame_num = Math.round(mousepct / frameinterval);

  background_y = -1 * frame_ht * (frame_num + 1);
  image.style.backgroundPositionY = background_y.toString() + "px";
}

function touch_animate(e){
  image_right_coord = image_bcr.right;
  image_left_coord = image_bcr.left;
  currentX = e.touches[0].clientX;
  mouse_depth = Math.max(image_right_coord - currentX, 0);

  mousepct = mouse_depth / image_bcr.width;
  
  frame_num = Math.round(mousepct / frameinterval);
  
  background_y = -1 * frame_ht * (frame_num + 1);
  image.style.backgroundPositionY = background_y.toString() + "px";
}

image.onmousemove = animate;
image.ontouchmove = touch_animate;

This page’s stylesheet is also straightforward, but it sets the background to concat_v.png using background-image:

/* source: milkslap-milkslap.scss */
body {
  margin: 0;
  padding: 0;
  overflow: hidden; }

a {
  color: inherit; }

.center {
  width: 1080px;
  height: 720px;
  margin: 0 auto; }

#image {
  height: 720px;
  margin-top: 5%;
  margin-bottom: 20px;
  background-image: url(concat_v.png);
  background-position: 0 0; }

#foot {
  margin-bottom: 5px;
  color: #999999; }
  #foot h1 {
    font-family: serif;
    font-weight: normal;
    font-size: 1rem;
    text-align: center; }

Next, I retrieved concat_v.png, which is a very tall PNG image containing the frames used in the animation. I downloaded it and used exiftool, which didn’t reveal anything useful to me.

Since this was a forensics challenge and not worth a lot of points, I had a feeling that it was likely another steganography challenge, so I just started running decoders against this image. zsteg ended up solving this puzzle:

Solving with zsteg.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s