Separating challenges

This commit is contained in:
Nanne Baars 2017-04-09 02:30:13 +02:00
parent 4feae018d3
commit ec338326ea
14 changed files with 535 additions and 110 deletions

View File

@ -8,7 +8,6 @@ import org.owasp.webgoat.lessons.NewLesson;
import java.net.URL;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
@ -24,8 +23,8 @@ public class PluginResource {
private final URL location;
private final List<Class> classes;
public Optional<Class> getLesson() {
return classes.stream().filter(c -> c.getSuperclass() == NewLesson.class).findFirst();
public List<Class> getLessons() {
return classes.stream().filter(c -> c.getSuperclass() == NewLesson.class).collect(Collectors.toList());
}
public List<Class<Endpoint>> getEndpoints() {

View File

@ -67,13 +67,18 @@ public class PluginsLoader {
List<AbstractLesson> lessons = Lists.newArrayList();
for (PluginResource plugin : findPluginResources()) {
try {
Class lessonClazz = plugin.getLesson()
.orElseThrow(() -> new PluginLoadingFailure("Plugin resource does not contain lesson"));
NewLesson lesson = (NewLesson) lessonClazz.newInstance();
List<Class<AssignmentEndpoint>> assignments = plugin.getAssignments();
lesson.setAssignments(createAssignment(assignments));
lessons.add(lesson);
pluginEndpointPublisher.publish(plugin.getEndpoints());
plugin.getLessons().forEach(c -> {
NewLesson lesson = null;
try {
lesson = (NewLesson) c.newInstance();
} catch (Exception e) {
log.error("Error while loading:" + c, e);
}
List<Class<AssignmentEndpoint>> assignments = plugin.getAssignments();
lesson.setAssignments(createAssignment(assignments));
lessons.add(lesson);
pluginEndpointPublisher.publish(plugin.getEndpoints());
});
} catch (Exception e) {
log.error("Error in loadLessons: ", e);
}

View File

@ -1,8 +1,9 @@
package org.owasp.webgoat.plugin;
package org.owasp.webgoat.plugin.challenge1;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.plugin.Flag;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@ -42,7 +43,7 @@ import static org.owasp.webgoat.plugin.SolutionConstants.PASSWORD;
* @since August 11, 2016
*/
@AssignmentPath("/challenge/1")
public class Challenge1 extends AssignmentEndpoint {
public class Assignment1 extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public

View File

@ -1,4 +1,4 @@
package org.owasp.webgoat.plugin;
package org.owasp.webgoat.plugin.challenge1;
import com.google.common.collect.Lists;
import org.owasp.webgoat.lessons.Category;
@ -10,7 +10,7 @@ import java.util.List;
* @author nbaars
* @since 3/21/17.
*/
public class Challenge extends NewLesson {
public class Challenge1 extends NewLesson {
@Override
public Category getDefaultCategory() {
@ -29,11 +29,11 @@ public class Challenge extends NewLesson {
@Override
public String getTitle() {
return "challenge.title";
return "challenge1.title";
}
@Override
public String getId() {
return "Challenge";
return "Challenge1";
}
}

View File

@ -1,8 +1,9 @@
package org.owasp.webgoat.plugin;
package org.owasp.webgoat.plugin.challenge2;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.plugin.Flag;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@ -17,7 +18,7 @@ import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
* @since 4/6/17.
*/
@AssignmentPath("/challenge/2")
public class Challenge2 extends AssignmentEndpoint {
public class Assignment2 extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public

View File

@ -0,0 +1,39 @@
package org.owasp.webgoat.plugin.challenge2;
import com.google.common.collect.Lists;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import java.util.List;
/**
* @author nbaars
* @since 3/21/17.
*/
public class Challenge2 extends NewLesson {
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 10;
}
@Override
public String getTitle() {
return "challenge2.title";
}
@Override
public String getId() {
return "Challenge2";
}
}

View File

@ -1,4 +1,4 @@
package org.owasp.webgoat.plugin;
package org.owasp.webgoat.plugin.challenge2;
import com.beust.jcommander.internal.Lists;
import lombok.AllArgsConstructor;

View File

@ -0,0 +1,109 @@
package org.owasp.webgoat.plugin.challenge3;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.EvictingQueue;
import org.joda.time.DateTime;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.plugin.Flag;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
import static org.springframework.http.MediaType.ALL_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
/**
* @author nbaars
* @since 4/8/17.
*/
@AssignmentPath("/challenge/3")
public class Assignment3 extends AssignmentEndpoint {
@Autowired
private WebSession webSession;
private static final EvictingQueue<Comment> comments = EvictingQueue.create(100);
static {
comments.add(new Comment("webgoat", DateTime.now().toString(), "Silly cat...."));
comments.add(new Comment("guest", DateTime.now().toString(), "I think I will use this picture in one of my projects."));
comments.add(new Comment("guest", DateTime.now().toString(), "Lol!! :-)."));
}
@RequestMapping(method = GET, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public Collection<Comment> retrieveComments() {
return comments;
}
@RequestMapping(method = POST, consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public AttackResult createNewComment(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception {
Comment comment = null;
AttackResult attackResult = failed().build();
if (APPLICATION_JSON_VALUE.equals(contentType)) {
comment = parseJson(commentStr);
comment.setDateTime(DateTime.now().toString());
comment.setUser(webSession.getUserName());
}
if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) {
comment = parseXml(commentStr);
comment.setDateTime(DateTime.now().toString());
comment.setUser(webSession.getUserName());
}
if (comment != null) {
comments.add(comment);
if (checkSolution(comment)) {
attackResult = success().feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(2)).build();
}
}
return attackResult;
}
private boolean checkSolution(Comment comment) {
if (comment.getComment().contains("Congratulations you may now collect your flag")) {
comment.setComment("Congratulations to " + webSession.getUserName() + " for finding the flag!!");
return true;
}
return false;
}
public static Comment parseXml(String xml) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Comment.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, true);
xif.setProperty(XMLInputFactory.IS_VALIDATING, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, true);
XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(xml));
Unmarshaller unmarshaller = jc.createUnmarshaller();
return (Comment) unmarshaller.unmarshal(xsr);
}
private Comment parseJson(String comment) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(comment, Comment.class);
} catch (IOException e) {
return new Comment();
}
}
}

View File

@ -1,109 +1,39 @@
package org.owasp.webgoat.plugin.challenge3;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.EvictingQueue;
import org.joda.time.DateTime;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.plugin.Flag;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import com.google.common.collect.Lists;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
import static org.springframework.http.MediaType.ALL_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.util.List;
/**
* @author nbaars
* @since 4/8/17.
* @since 3/21/17.
*/
@AssignmentPath("/challenge/3")
public class Challenge3 extends AssignmentEndpoint {
public class Challenge3 extends NewLesson {
@Autowired
private WebSession webSession;
private static final EvictingQueue<Comment> comments = EvictingQueue.create(100);
static {
comments.add(new Comment("webgoat", DateTime.now().toString(), "Silly cat...."));
comments.add(new Comment("guest", DateTime.now().toString(), "I think I will use this picture in one of my projects."));
comments.add(new Comment("guest", DateTime.now().toString(), "Lol!! :-)."));
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@RequestMapping(method = GET, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public Collection<Comment> retrieveComments() {
return comments;
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@RequestMapping(method = POST, consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
@ResponseBody
public AttackResult createNewComment(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception {
Comment comment = null;
AttackResult attackResult = failed().build();
if (APPLICATION_JSON_VALUE.equals(contentType)) {
comment = parseJson(commentStr);
comment.setDateTime(DateTime.now().toString());
comment.setUser(webSession.getUserName());
}
if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) {
comment = parseXml(commentStr);
comment.setDateTime(DateTime.now().toString());
comment.setUser(webSession.getUserName());
}
if (comment != null) {
comments.add(comment);
if (checkSolution(comment)) {
attackResult = success().feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(2)).build();
}
}
return attackResult;
@Override
public Integer getDefaultRanking() {
return 10;
}
private boolean checkSolution(Comment comment) {
if (comment.getComment().contains("Congratulations you may now collect your flag")) {
comment.setComment("Congratulations to " + webSession.getUserName() + " for finding the flag!!");
return true;
}
return false;
@Override
public String getTitle() {
return "challenge3.title";
}
public static Comment parseXml(String xml) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Comment.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, true);
xif.setProperty(XMLInputFactory.IS_VALIDATING, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, true);
XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(xml));
Unmarshaller unmarshaller = jc.createUnmarshaller();
return (Comment) unmarshaller.unmarshal(xsr);
@Override
public String getId() {
return "Challenge3";
}
private Comment parseJson(String comment) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(comment, Comment.class);
} catch (IOException e) {
return new Comment();
}
}
}

View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_introduction.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_1.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="panel panel-default">
<div class="panel-heading">
<img th:src="@{/images/webgoat2.png}" class="img-thumbnail"/>
</div>
<div class="panel-body">
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/challenge/1"
style="width: 200px;"
enctype="application/json;charset=UTF-8">
<div class="form-group">
<label for="exampleInputEmail1" th:text="#{username}">Username</label>
<input autofocus="dummy_for_thymeleaf_parser" type="text" class="form-control"
id="exampleInputEmail1" placeholder="Username" name='username' value="admin"/>
</div>
<div class="form-group">
<label for="exampleInputPassword1" th:text="#{password}">Password</label>
<input type="password" class="form-control" id="exampleInputPassword1"
placeholder="Password"
name='password'/>
</div>
<button class="btn btn-primary btn-block" type="submit" th:text="#{sign.in}">Sign in</button>
</form>
</div>
</div>
<form class="form-inline" method="POST" name="form" action="/WebGoat/challenge/flag">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
style="font-size:20px"></i></div>
<input type="text" class="form-control" id="flagInput1"
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit flag</button>
</form>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_introduction.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_2.adoc"></div>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge2.css}"/>
<script th:src="@{/lesson_js/challenge2.js}" language="JavaScript"></script>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/challenge/2"
enctype="application/json;charset=UTF-8">
<input id="discount" type="hidden" value="0"/>
<div class="row">
<div class="col-xs-3 item-photo">
<img style="max-width:100%;" th:src="@{/images/samsung-black.jpg}"/>
</div>
<div class="col-xs-5" style="border:0px solid gray">
<h3>Samsung Galaxy S8</h3>
<h5 style="color:#337ab7"><a href="http://www.samsung.com">Samsung</a> ·
<small style="color:#337ab7">(124421 reviews)</small>
</h5>
<h6 class="title-price">
<small>PRICE</small>
</h6>
<h3 style="margin-top:0px;"><span>US $</span><span id="price">899</span></h3>
<div class="section">
<h6 class="title-attr" style="margin-top:15px;">
<small>COLOR</small>
</h6>
<div>
<div class="attr" style="width:25px;background:lightgrey;"></div>
<div class="attr" style="width:25px;background:black;"></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CAPACITY</small>
</h6>
<div>
<div class="attr2">64 GB</div>
<div class="attr2">128 GB</div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>QUANTITY</small>
</h6>
<div>
<div class="btn-minus"><span class="glyphicon glyphicon-minus"></span></div>
<input class="quantity" value="1"/>
<div class="btn-plus"><span class="glyphicon glyphicon-plus"></span></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CHECKOUT CODE</small>
</h6>
<!--
Checkout code: webgoat, owasp, owasp-webgoat
-->
<input name="checkoutCode" class="checkoutCode" value=""/>
</div>
<div class="section" style="padding-bottom:20px;">
<button type="submit" class="btn btn-success"><span style="margin-right:20px"
class="glyphicon glyphicon-shopping-cart"
aria-hidden="true"></span>Buy
</button>
<h6><a href="#"><span class="glyphicon glyphicon-heart-empty"
style="cursor:pointer;"></span>
Like</a></h6>
</div>
</div>
</div>
</form>
<br/>
<div>
<form class="form-inline" method="POST" name="form" action="/WebGoat/challenge/flag">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
style="font-size:20px"></i></div>
<input type="text" class="form-control" id="flagInpu2"
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit flag</button>
</form>
</div>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_introduction.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_3.adoc"></div>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge3.css}"/>
<script th:src="@{/lesson_js/challenge3.js}" language="JavaScript"></script>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="panel post">
<div class="post-heading">
<div class="pull-left image">
<img th:src="@{/images/avatar1.png}"
class="img-circle avatar" alt="user profile image"/>
</div>
<div class="pull-left meta">
<div class="title h5">
<a href="#"><b>John Doe</b></a>
uploaded a photo.
</div>
<h6 class="text-muted time">24 days ago</h6>
</div>
</div>
<div class="post-image">
<img th:src="@{images/cat.jpg}" class="image" alt="image post"/>
</div>
<div class="post-description">
</div>
<div class="post-footer">
<div class="input-group">
<input class="form-control" id="commentInput" placeholder="Add a comment" type="text"/>
<span class="input-group-addon">
<i id="postComment" class="fa fa-edit"></i>
</span>
</div>
<ul class="comments-list">
<div id="list">
</div>
</ul>
</div>
</div>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_introduction.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:Challenge_4.adoc"></div>
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge2.css}"/>
<script th:src="@{/lesson_js/challenge2.js}" language="JavaScript"></script>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/challenge/4"
enctype="application/json;charset=UTF-8">
<input id="discount" type="hidden" value="0"/>
<div class="row">
<div class="col-xs-3 item-photo">
<img style="max-width:100%;" th:src="@{/images/samsung-black.jpg}"/>
</div>
<div class="col-xs-5" style="border:0px solid gray">
<h3>Samsung Galaxy S8</h3>
<h5 style="color:#337ab7"><a href="http://www.samsung.com">Samsung</a> ·
<small style="color:#337ab7">(124421 reviews)</small>
</h5>
<h6 class="title-price">
<small>PRICE</small>
</h6>
<h3 style="margin-top:0px;"><span>US $</span><span id="price">899</span></h3>
<div class="section">
<h6 class="title-attr" style="margin-top:15px;">
<small>COLOR</small>
</h6>
<div>
<div class="attr" style="width:25px;background:lightgrey;"></div>
<div class="attr" style="width:25px;background:black;"></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CAPACITY</small>
</h6>
<div>
<div class="attr2">64 GB</div>
<div class="attr2">128 GB</div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>QUANTITY</small>
</h6>
<div>
<div class="btn-minus"><span class="glyphicon glyphicon-minus"></span></div>
<input class="quantity" value="1"/>
<div class="btn-plus"><span class="glyphicon glyphicon-plus"></span></div>
</div>
</div>
<div class="section" style="padding-bottom:5px;">
<h6 class="title-attr">
<small>CHECKOUT CODE</small>
</h6>
<!--
Checkout code: webgoat, owasp, owasp-webgoat
-->
<input name="checkoutCode" class="checkoutCode" value=""/>
</div>
<div class="section" style="padding-bottom:20px;">
<button type="submit" class="btn btn-success"><span style="margin-right:20px"
class="glyphicon glyphicon-shopping-cart"
aria-hidden="true"></span>Buy
</button>
<h6><a href="#"><span class="glyphicon glyphicon-heart-empty"
style="cursor:pointer;"></span>
Like</a></h6>
</div>
</div>
</div>
</form>
<br/>
<div>
<form class="form-inline" method="POST" name="form" action="/WebGoat/challenge/flag">
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
style="font-size:20px"></i></div>
<input type="text" class="form-control"
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit flag</button>
</form>
</div>
<br/>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -1,2 +1,5 @@
challenge.title=WebGoat Challenge
challenge1.title=Admin lost password
challenge2.title=Get it for free
challenge3.title=Photo comments
challenge.solved=Congratulations, you solved the challenge. Here is your flag: {0}